Условие
Дана таблица Orders(customer_id, product_name, order_date). Напишите запрос, выявляющий всех клиентов, купивших iPhone, но не купивших Airpods, чтобы команда маркетинга могла отправить им предложение.
Решение
Подход
Классический «антиджойн»: набор A минус набор B. Три эквивалентных способа: NOT EXISTS, LEFT JOIN ... IS NULL, EXCEPT.
Реализация
-- Вариант 1: NOT EXISTS (предпочтительно, читаемо)
SELECT DISTINCT o.customer_id
FROM Orders o
WHERE o.product_name = 'iPhone'
AND NOT EXISTS (
SELECT 1 FROM Orders o2
WHERE o2.customer_id = o.customer_id
AND o2.product_name = 'Airpods'
);
-- Вариант 2: EXCEPT
SELECT DISTINCT customer_id FROM Orders WHERE product_name = 'iPhone'
EXCEPT
SELECT DISTINCT customer_id FROM Orders WHERE product_name = 'Airpods';
-- Вариант 3: LEFT JOIN ... IS NULL
SELECT DISTINCT i.customer_id
FROM Orders i
LEFT JOIN Orders a
ON a.customer_id = i.customer_id AND a.product_name = 'Airpods'
WHERE i.product_name = 'iPhone'
AND a.customer_id IS NULL;Подводные камни
- Без
DISTINCTбудет дублирование, если клиент купил iPhone несколько раз. - Чувствительность к регистру:
'iPhone'vs'iphone'— лучшеLOWER(). - Если айфонов несколько моделей (
iPhone 14,iPhone 15) —LIKE 'iPhone%'. NOT INопасен приNULLв подзапросе — он вернёт пустоту.NOT EXISTSв этом случае безопаснее.
Эталонный ответ
NOT EXISTS или EXCEPT на customer_id, отфильтровав по продукту в каждой ветке.