简体   繁体   English

如何选择所有联接记录都不符合条件的记录

[英]How to select records where all joined records aren't a match for criteria

I've a setup with the following tables (using MySQL): 我使用以下表格进行了设置(使用MySQL):

  • orders , which have many: orders ,其中有很多:
  • a join table order_items , which have one from the: order_itemsorder_items ,其中一个来自:
  • products table products

I've written a query to select orders where all their products are of a certain type : 我写了一个查询来选择所有 products均为某种type orders

SELECT orders.* FROM orders 
INNER JOIN order_items ON order_items.order_id = orders.id   
INNER JOIN products ON products.id = order_items.product_id     
WHERE products.type = 'FooProduct'
AND (
  NOT EXISTS (
    SELECT null
    FROM products
    INNER JOIN order_items ON order_items.product_id = products.id
    WHERE order_items.order_id = orders.id
    AND products.type != 'FooProduct'
  )
 )

I run similar a couple of times: firstly to get orders comprised of all FooProduct s, and again to get orders with all BarProduct s. 我也进行了两次类似的操作:首先要获取包含所有FooProduct的订单,然后再次获取所有BarProduct的订单。

My sticking point has been generating a third query to get all other orders, ie where all their products' types are not exclusively FooProduct s, or exclusively BarProduct s (aka a mix of the two, or other product types). 我的症结一直是生成第三个查询以获取所有其他订单,即,其所有产品的类型都不都是FooProductBarProduct (又是两种或其他产品类型的混合)。

So, my question is how can I get all records where all product types aren't exclusively FooProduct s or exclusively BarProduct . 所以,我的问题是如何获得的所有记录, 所有的产品类型是不完全FooProduct S或专门BarProduct


Here's a little example data, from which I'd like to return the orders with the IDs 3 and 4: 以下是一些示例数据,我想从中返回ID为3和4的订单:

- orders
id
 1
 2
 3
 4

-- order_items

id order_id product_id
 1        1          1
 2        1          1
 3        2          2
 4        2          2
 5        3          3
 6        3          4
 7        4          1
 8        4          2

-- products
id type
 1 'FooProduct'
 2 'BarProduct'
 3 'OtherProduct'
 4 'YetAnotherProduct'

I've attempted this, awfully so placing as a subtext, with the following in place of the existing AND (even the syntax is way off): 我已经尝试过了,因此非常遗憾地将其放置为子文本,并用以下内容代替了现有的AND (即使语法很不正确):

NOT HAVING COUNT(order_items.*) = (
  SELECT null
        FROM products
        INNER JOIN order_items ON  order_items.product_id = products.id
        WHERE order_items.order_id = orders.id
        AND products.type IN ('FooProduct', 'BarProduct')
)

Instead of using Correlated subqueries, you can use Having and conditional aggregation function based filtering. 而不是使用相关子查询的,可以使用Having和条件聚合函数基于内容的过滤。

products.type IN ('FooProduct', 'BarProduct') will return 0 if a product type is none of them. 如果产品类型都不是,那么products.type IN ('FooProduct', 'BarProduct')将返回0。 We can use Sum() function on it, for further filtering. 我们可以在其上使用Sum()函数进行进一步的过滤。

Try the following instead: 请尝试以下操作:

SELECT orders.order_id 
FROM orders 
INNER JOIN order_items ON order_items.order_id = orders.id   
INNER JOIN products ON products.id = order_items.product_id 
GROUP BY orders.order_id 
HAVING SUM(products.type IN ('FooProduct', 'BarProduct')) < COUNT(*)

For the case, where you are looking for orders which has only FooProduct type, you can use the following instead: 对于这种情况,如果要查找仅具有FooProduct类型的订单,则可以改用以下内容:

SELECT orders.order_id 
FROM orders 
INNER JOIN order_items ON order_items.order_id = orders.id   
INNER JOIN products ON products.id = order_items.product_id 
GROUP BY orders.order_id 
HAVING SUM(products.type <> 'FooProduct') = 0

Another possible approach is: 另一种可能的方法是:

SELECT orders.order_id 
FROM orders 
INNER JOIN order_items ON order_items.order_id = orders.id   
INNER JOIN products ON products.id = order_items.product_id 
GROUP BY orders.order_id 
HAVING SUM(products.type = 'FooProduct') = COUNT(*)

You can use aggregation and a having clause for this: 您可以为此使用聚合和having子句:

SELECT o.*
FROM orders o INNER JOIN
     order_items oi
     ON oi.order_id = o.id INNER JOIN
     products p
     ON p.id = oi.product_id   
GROUP BY o.id  -- OK assuming `id` is the primary key
HAVING SUM(p.type NOT IN ('FooProduct', 'BarProduct')) > 0;  -- at least one other product 

Actually, that is not quite right. 实际上,那是不正确的。 This gets orders that have some other product, but it doesn't pick up orders that are mixes only of foo and bar. 这会获得具有其他产品的订单,但不会选择仅由foo和bar混合而成的订单。 I think this gets the others: 我认为这会吸引其他人:

HAVING SUM(p.type = 'FooProduct') < COUNT(*) AND
       SUM(p.type = 'BarProduct') < COUNT(*) 

This is a relational division problem. 这是一个关系划分问题。
One solution to find orders where all products are of a given type is this: 查找所有给定类型产品的订单的一种解决方案是:

SELECT *
FROM orders
INNER JOIN order_items ON order_items.order_id = orders.id
INNER JOIN products ON products.id = order_items.product_id
WHERE orders.id IN (
    SELECT order_items.order_id
    FROM order_items
    INNER JOIN products ON products.id = order_items.product_id
    GROUP BY order_items.order_id
    HAVING COUNT(CASE WHEN products.type = 'FooProduct' THEN 1 END) = COUNT(*)
)

Tweak the above just a little to find orders where all products are from a list of given types is this: 稍微调整一下上面的内容,即可从给定类型的列表中找到所有产品都来自的订单:

HAVING COUNT(CASE WHEN products.type IN ('FooProduct', 'BarProduct') THEN 1 END) = COUNT(*)

And to find all orders where all products match all types from a given list is this: 从给定列表中查找所有产品与所有类型匹配的所有订单的方法是:

HAVING COUNT(CASE WHEN products.type IN ('FooProduct', 'BarProduct') THEN 1 END) = COUNT(*)
AND    COUNT(DISTINCT products.type) = 2

DB Fiddle with tests DB Fiddle测试

This is a basic solution, not so efficient but easy: 这是一个基本解决方案,效率不高,但很容易:

SELECT * FROM orders WHERE id NOT IN (
    SELECT orders.id FROM orders 
    INNER JOIN order_items ON order_items.order_id = orders.id   
    INNER JOIN products ON products.id = order_items.product_id     
    WHERE products.type = 'FooProduct'
    AND (
      NOT EXISTS (
        SELECT null
        FROM products
        INNER JOIN order_items ON order_items.product_id = products.id
        WHERE order_items.order_id = orders.id
        AND products.type != 'FooProduct'
      )
 )
) AND id NOT IN (
    SELECT orders.id FROM orders 
    INNER JOIN order_items ON order_items.order_id = orders.id   
    INNER JOIN products ON products.id = order_items.product_id     
    WHERE products.type = 'BarProduct'
    AND (
      NOT EXISTS (
        SELECT null
        FROM products
        INNER JOIN order_items ON order_items.product_id = products.id
        WHERE order_items.order_id = orders.id
        AND products.type != 'BarProduct'
      )
 )
)

I would suggest using count(distinct) in joined subselect like this: 我建议像这样在连接的子选择中使用count(distinct):

SELECT orders.*
FROM orders 
inner join (
    SELECT orderid, max(products.type) as products_type
    FROM order_items
    INNER JOIN products ON products.id = order_items.product_id
    GROUP BY orderid
    -- distinct count of different products = 1 
    --    -> all order items are for the same product type
    HAVING COUNT(distinct products.type ) = 1 
    -- alternative is:
    -- min(products.type )=max(products.type )
) as tmp on tmp.orderid=orders.orderid 
WHERE 1=1
-- if you want only single type product orders for some specific product
and tmp.products_type = 'FooProduct'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 选择所有连接的行都匹配的记录 - Selecting records where all joined rows match 如何根据条件选择一个表中的所有记录,而第二个表中没有记录 - How to select all records in one table where no records in second table based on criteria MySQL:选择连接表匹配所有值的记录 - MySQL: Select records where joined table matches ALL values 在联接表中选择所有不满足某些条件的记录 - Select all records don't meet certain conditions in a joined table 如何选择与联接表中定义的条件匹配的记录? - How to select records who match criteria defined in a join table? 如何选择超过4条条件的记录 - How to Select records with over 4 criteria 如何获得 MySQL JOIN 的结果,其中记录满足连接表中的值标准? - How do I get results of a MySQL JOIN where records meet a value criteria in joined table? SQL查询以获取符合所有条件的记录 - SQL query to get records that match ALL the criteria 选择在联接表中没有特定记录的记录 - Select records which doesn't have specific records in joined table 如何从一个表中获取 select 条记录,其中第二个表的一列中所有记录的值与第一个表的多个列中的任何一个相匹配? - How to select records from one table where values from all the records in a column of second table match any of the multiple columns of first table?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM