⚠️ SQL Ловушка: почему оператор NOT IN ломается, а EXISTS работает:
Рассмотрим классическую проблему с которой встречались многие.
📊 Пример данных:
Таблица orders:
order_id
--------
1
2
3
4
И таблица delivered_orders:
order_id
--------
1
2
NULL ← вот эта засада!
⭐️ Задача: Найти не доставленные заказы.
❌ Почему оператор NOT IN в данном случае выдаст не верный результат:
Пишем запрос:
SELECT *
FROM orders
WHERE order_id NOT IN (SELECT order_id FROM delivered_orders);
Подзапрос вернет: (1, 2, NULL)
Итоговый результат - ПУСТАЯ ВЫБОРКА!
Почему сломалось? Давайте посмотрим на логику работы оператора not in для строки 3 в таблице orders:
1️⃣ 3 ≠ 1 AND 3 ≠ 2 AND 3 ≠ NULL
Переведем эти условия на булевую логику:
2️⃣3 ≠ 1 (True) AND 3 ≠ 2 (True) AND 3 ≠ NULL (UNKNOWN) → UNKNOWN (False)
То есть для любой строки условие не будет выполнено из-за NULL
✔️ Что делать, чтобы не допустить такой проблемы?
1️⃣Ответ - в подзапросе в условии where добавить is not null:
SELECT *
FROM orders
WHERE order_id NOT IN (SELECT order_id FROM delivered_orders where order_id is not null);
2️⃣Ответ - использовать оператор NOT EXISTS:
Пишем запрос:
SELECT *
FROM orders o
WHERE NOT EXISTS (
SELECT 1
FROM delivered_orders d
WHERE d.order_id = o.order_id
);
Сравнение выполняется построчно; запись с NULL не совпадает ни с одним order_id, поэтому итог снова 3 и 4 — без риска забыть фильтр IS NOT NULL.
Итог:
😎 Если эта инструкция вам помогла, то кидайте 🔥 или ❤️!
Встречались с такой проблемой и поняли как ее решить?