Условие:
Есть две таблицы:
CREATE TABLE employees (
id INT PRIMARY KEY,
name TEXT,
department_id INT
);
CREATE TABLE departments (
id INT PRIMARY KEY,
name TEXT,
is_active BOOLEAN
);
✔️ Задание:
Выведите всех сотрудников, которые работают в неактивных отделах.
Если department_id у сотрудника NULL, таких сотрудников выводить не нужно.
❗️Подводный камень:
Решение, которое интуитивно приходит в голову, не работает правильно:
SELECT *
FROM employees
WHERE department_id NOT IN (
SELECT id FROM departments WHERE is_active = true
);
📉 Почему это ошибка:
Если в departments есть хотя бы одна строка, где is_active = true, но id = NULL, то NOT IN (...) будет сравнивать с NULL, а NULL NOT IN (...) всегда возвращает UNKNOWN, то есть — ничего не вернёт.
✅ Правильное решение:
SELECT e.*
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.is_active = false;
💡 Почему работает:
JOIN отсекает NULL по department_id сразу.
Фильтр по is_active = false работает без ловушек NULL.
Сотрудники без департамента автоматически исключаются.
🔎 Усложнение для профи:
Что произойдёт, если в таблице departments есть id = NULL, is_active = true?
Ответ: ничего — JOIN по NULL никогда не срабатывает. Но если используете NOT EXISTS, нужно быть осторожным.
🧩 Вывод:
Когда дело касается NOT IN и NULL, всегда проверяйте подзапрос. Лучше переходите на JOIN или NOT EXISTS:
SELECT e.*
FROM employees e
WHERE EXISTS (
SELECT 1
FROM departments d
WHERE d.id = e.department_id AND d.is_active = false
);
📌 Запомни:
NULL ломает IN / NOT IN, но не ломает JOIN / EXISTS.
➡ SQL Community | Чат