Как найти, если список / набор содержится в другом списке

StackOverflow https://stackoverflow.com//questions/12652037

  •  11-12-2019
  •  | 
  •  

Вопрос

У меня есть список идентификаторов продукта, и я хочу выяснить, какие заказы содержат все эти продукты.Таблица заказов структурирована так:

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, есть ли другая база данных, которая имеет эту функциональность?

Это было полезно?

Решение

Вы были закрыты

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

Что касается вопроса вашего «из любопытства» в реляционной алгебре. Это достигается просто с Разделение .AFAIK Нет RDBMS внедрил любое расширение, которое делает это как просто в SQL.

Другие советы

У меня есть предпочтение для выполнения заданных сравнений только в пункте имеющих:

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 (просто изменив «и» и «или» или «).Или 333 и 555 или 222 без 555.

Во-вторых, когда вы создаете запрос, вам нужно только поместить условие в одном месте, в пункте having.

Предполагая, что ваша база данных нормализована правильно, то есть нет дубликата продукта на данном порядке

mysqlism:

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
.

Live Test: http://www.sqlfiddle.com/#!2/fa1ad/ 5

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top