如何选择所有加入的记录都不符合条件的记录

xdyibdwo  于 2021-06-18  发布在  Mysql
关注(0)|答案(5)|浏览(334)

我使用以下表格进行了设置(使用mysql): orders ,有很多:
联接表 order_items ,其中一个来自: products table
我编写了一个查询来选择 orders 他们所有的 products 有一定的 type :

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'
  )
 )

我运行过几次类似的操作:首先是获取包含所有 FooProduct s、 再次得到所有人的命令 BarProduct s。
我的关键点是生成第三个查询来获取所有其他订单,即他们的所有产品类型都不是独占的 FooProduct s、 或完全 BarProduct s(也称为这两种产品的混合,或其他产品类型)。
所以,我的问题是,在所有产品类型都不是独占的情况下,如何获取所有记录 FooProduct s或独占 BarProduct .
下面是一个小示例数据,我想从中返回带有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'

我尝试过这样做,把它作为一个潜台词,用下面的内容代替现有的 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')
)
ojsjcaue

ojsjcaue1#

这是一个关系划分问题。
查找所有产品都属于给定类型的订单的一种解决方案是:

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(*)
)

稍微调整一下上面的内容,找到所有产品都来自给定类型列表的订单是这样的:

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

要查找所有产品与给定列表中所有类型匹配的所有订单,请执行以下操作:

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

干扰测试

v6ylcynt

v6ylcynt2#

您可以使用 Having 以及基于条件聚集函数的过滤。 products.type IN ('FooProduct', 'BarProduct') 如果一个产品类型不是其中任何一个,则返回0。我们可以用 Sum() 函数,用于进一步过滤。
请尝试以下操作:

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(*)

在这种情况下,您要寻找的订单只有 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

另一种可能的方法是:

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(*)
n7taea2i

n7taea2i3#

我建议在joined subselect中使用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'
5rgfhyps

5rgfhyps4#

可以使用聚合和 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

事实上,这并不完全正确。这会得到一些其他产品的订单,但它不会接受只有foo和bar混合的订单。我想这会让其他人:

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

whlutmcx5#

这是一个基本的解决方案,虽然效率不高,但很简单:

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'
      )
 )
)

相关问题