
NOT IN — не противоположность IN: что в запросе ломает один NULL
badcasedaily1 2 часа назад NOT IN — не противоположность IN: что в запросе ломает один NULL Средний 6 мин 3.1K Блог компании OTUS SQL * Программирование * Базы данных * PostgreSQL * Туториал Привет, Хабр!В SQL есть...
<5 — 2026'da uzaya kaç SpaceX Starship fırlatması ulaşacak?
В сфере искусственного интеллекта произошло заметное событие. badcasedaily1 2 часа назад NOT IN — не противоположность IN: что в запросе ломает один NULL Средний 6 мин 3. 1K Блог компании OTUS SQL * Программирование * Базы данных * PostgreSQL * Туториал Привет, Хабр! В SQL есть отдельный класс ошибок, неприятных именно тем, что они никак себя не проявляют: база не выдаёт исключения, не пишет предупреждения — запрос просто возвращает не то, что нужно.
Чаще всего это пустой результат там, где вы ожидаете десятки строк. Один из самых распространённых случаев — NOT IN в сочетании с NULL. Возьмём задачу: найти сотрудников, которые никем не руководят.
Технические детали
В таблице employees есть поле manager_id — ссылка на начальника. Рассуждение простое: руководитель — это тот, кто хотя бы раз встречается в manager_id, а значит, не руководители — все, кого там нет. Запрос пишется почти сам собой:SELECT name FROM employees WHERE id NOT IN (SELECT manager_id FROM employees);Вы запускаете его и получаете ноль строк, хотя точно знаете: обычных сотрудников в компании большинство, и в выборку они обязаны попасть.
Логично заподозрить данные или сам запрос и для проверки заменить NOT IN на IN — посмотреть хотя бы на руководителей. IN отрабатывает корректно. А NOT IN на тех же данных упрямо возвращает пустоту.
Исключения при этом нет, синтаксис безупречен, поэтому причину найти непросто. Дальше разберём, почему NOT IN ломается из‑за одного‑единственного NULL, почему IN рядом продолжает работать корректно и почему NOT IN, вопреки названию, не противоположность IN. ПримерПять сотрудников, одна простая иерархия:CREATE TABLE employees ( id int PRIMARY KEY, name text, manager_id int ); INSERT INTO employees VALUES (1, 'Алексей', NULL), -- директор, начальника нет (2, 'Борис', 1), (3, 'Вера', 1), (4, 'Глеб', 2), (5, 'Дина', 2);Кто здесь руководитель?
Отраслевые последствия
Тот, на кого ссылаются. В колонке manager_id встречаются 1 и 2 — значит, руководят Алексей и Борис. Остальные трое — Вера, Глеб и Дина — никем не командуют.
Их мы и хотим получить. SELECT name FROM employees WHERE id NOT IN (SELECT manager_id FROM employees); name ------ (0 rows)Ноль. Не Вера с Глебом и Диной, а пусто.
Притом что IN на тех же данных отрабатывает безупречно:SELECT name FROM employees WHERE id IN (SELECT manager_id FROM employees); name --------- Алексей Борис (2 rows)Разворачиваем NOT INПодзапрос SELECT manager_id FROM employees возвращает набор значений: NULL, 1, 1, 2, 2. Тот самый NULL — от Алексея, у которого начальника нет. Теперь развернём NOT IN в то, чем он работает под капотом.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





