3

我有一个产品 ID 列表,我想找出哪些订单包含所有这些产品。Orders 表的结构如下:

order_id | product_id
----------------------
1        | 222
1        | 555
2        | 333

显然,我可以通过 PHP 中的一些循环来做到这一点,但我想知道是否有一种优雅的方法可以纯粹在 mysql 中做到这一点。我理想的幻想查询是这样的:

SELECT order_id
FROM orders
WHERE (222,555) IN GROUP_CONCAT(product_id)
GROUP BY order_id

有没有希望或者我应该去读托尔金?:) 另外,出于好奇,如果在 mysql 中不可能,是否还有其他数据库具有此功能?

4

4 回答 4

4

你很亲近

SELECT order_id
FROM orders
WHERE product_id in (222,555) 
GROUP BY order_id
HAVING COUNT(DISTINCT product_id) = 2

关于您在关系代数中的“出于好奇”问题,这可以通过除法来实现。AFAIK 没有 RDBMS 实现了任何扩展,使其在 SQL 中变得如此简单。

于 2012-09-29T10:45:25.377 回答
1

我倾向于只在have子句中进行集合比较:

select order_id
from orders
group by order_id
having sum(case when product_id = 222 then 1 else 0 end) > 0 and
       sum(case when product_id = 555 then 1 else 0 end) > 0

这就是说:给我所有订单,其中订单至少有一种产品 222 和至少一种产品 555。

我更喜欢这个有两个原因。首先是普遍性。您可以安排更复杂的条件,例如 222 或 555(只需将“and”更改为“or”)。或者,333 和 555 或 222 没有 555。

其次,当您创建查询时,您只需将条件放在一个地方,即having子句中。

于 2012-09-29T14:26:39.287 回答
1
CREATE TABLE orders
        ( order_id INTEGER NOT NULL
        , product_id INTEGER NOT NULL
        );
INSERT INTO orders(order_id,product_id) VALUES
 (1, 222 ) , (1, 555 ) , (2, 333 )
, (3, 222 ) , (3, 555 ) , (3, 333 ); -- order#3 has all the products

CREATE TABLE products AS (SELECT DISTINCT product_id FROM orders);

SELECT *
FROM orders o1
   --
   -- There should not exist a product
   -- that is not part of our order.
   --
WHERE NOT EXISTS (
        SELECT *
        FROM products pr
        WHERE 1=1
           -- extra clause: only want producs from a literal list
        AND pr.product_id IN (222,555,333)
           --  ... that is not part of our order...
        AND NOT EXISTS ( SELECT *
                FROM orders o2
                WHERE o2.product_id = pr.product_id
                AND o2.order_id = o1.order_id
                )
        );

结果:

 order_id | product_id 
----------+------------
        3 |        222
        3 |        555
        3 |        333
(3 rows)
于 2012-09-29T15:14:03.867 回答
1

假设您的数据库已正确规范化,即给定订单上没有重复的产品

mysql主义:

select order_id
from orders
group by order_id
having sum(product_id in (222,555)) = 2

标准 SQL:

select order_id
from orders
group by order_id
having sum(case when product_id in (222,555) then 1 end) = 2

如果有重复:

CREATE TABLE tbl
    (`order_id` int, `product_id` int)
;

INSERT INTO tbl
    (`order_id`, `product_id`)
VALUES
    (1, 222),
    (1, 555),
    (2, 333),
    (1, 555)
;

然后这样做:

select order_id
from tbl
group by order_id
having count(distinct case when product_id in (222,555) then product_id end) = 2

现场测试:http ://www.sqlfiddle.com/#!2/fa1ad/5

于 2012-09-29T14:42:36.350 回答