Клиенты, заказавшие каждый продукт из заданной категории
Таблицы orders(customer_id, product_id) и products(id, category_id). Для заданного category_id верните клиентов, заказавших каждый продукт этой категории — задача реляционного деления. Клиент, у которого нет хотя бы одного продукта, исключается.
-- клиенты, заказавшие ВСЕ продукты заданной категории
Напишите запрос.
Группируют заказы клиента в категории и оставляют тех, чьё число различных продуктов равно итогу категории — HAVING COUNT(DISTINCT product_id) = (SELECT COUNT(*) FROM products WHERE category_id = :cat). DISTINCT не даёт повторам завысить счёт.
- ✗Использовать IN, возвращающий заказавших любой продукт, а не все
- ✗Считать без DISTINCT, и повторные заказы завышают совпадение
- ✗Сравнивать через >= вместо =, пропуская лишние продукты
- →Как формулировка с двойным NOT EXISTS выразит то же деление?
- →Почему DISTINCT необходим, если клиент может заказать один продукт повторно?
This is a relational-division query: find the customers whose set of ordered products contains the whole set of a category's products. The count-based formulation is the clearest:
SELECT o.customer_id
FROM orders o
JOIN products p ON p.id = o.product_id
WHERE p.category_id = :cat
GROUP BY o.customer_id
HAVING COUNT(DISTINCT o.product_id)
= (SELECT COUNT(*) FROM products WHERE category_id = :cat);
Restricting the join to the category means each customer's group holds only their category orders. COUNT(DISTINCT o.product_id) is how many distinct category products they bought; it must equal the category's total product count. DISTINCT is essential — without it, a customer who reordered one product would count it twice and could match on >= while still missing another product. An equivalent double-NOT EXISTS phrasing ("no product of the category that the customer has not ordered") returns the same set.