SQL18 января 2026 г.1.75K

Ловушка NULL и NOT IN в SQL: как не потерять данные

Коротко

NULL в SQL означает «неизвестно», а не «пусто». Из-за этого строки с NULL молча выпадают из результатов при использовании NOT IN — если не знать об этом, можно получить неверную выборку.

NULL в SQL — один из самых частых источников неочевидных багов. Особенно коварно он ведёт себя в связке с оператором NOT IN: строки, которые вы ожидаете увидеть в результате, просто исчезают без ошибок и предупреждений.

NULL — это не пустое значение

В SQL NULL не означает пустую строку или ноль. NULL означает «неизвестно». Это принципиальное различие, которое влияет на результаты любых сравнений с участием NULL.

SQL использует трёхзначную логику: результат условия может быть TRUE, FALSE или UNKNOWN. В результирующую выборку попадают только строки, для которых условие вернуло TRUE. UNKNOWN ведёт себя так же, как FALSE — строка в выборку не попадает.

Как NOT IN обрабатывает NULL

Рассмотрим поведение оператора NOT IN при сравнении разных значений со списком ('Москва'):

  • 'Москва' NOT IN ('Москва') → FALSE (значение есть в списке, в выборку не попадает)
  • 'Питер' NOT IN ('Москва') → TRUE (значения нет в списке, строка попадает в выборку)
  • NULL NOT IN ('Москва') → UNKNOWN (сравнение с NULL всегда даёт UNKNOWN, строка не попадает в выборку)

Именно поэтому строки, где проверяемый столбец равен NULL, тихо исчезают из результата: условие не возвращает TRUE, и фильтр их отсекает.

Как сохранить строки с NULL в выборке

Если нужно, чтобы строки с NULL также попадали в результат, необходимо явно обработать этот случай через дополнительное условие:

  • Добавьте OR city IS NULL к условию фильтрации
  • Пример: WHERE city NOT IN ('Москва') OR city IS NULL
  • Альтернатива — использовать NOT EXISTS вместо NOT IN: он корректнее обрабатывает NULL в подзапросах

Что сделать на практике

  • Перед использованием NOT IN убедитесь, что в фильтруемом столбце нет NULL, или явно учтите этот случай
  • Проверяйте количество строк до и после фильтрации — неожиданное расхождение часто указывает на проблему с NULL
  • В подзапросах с NOT IN особенно опасна ситуация, когда подзапрос возвращает хотя бы один NULL: в этом случае внешний запрос вернёт пустой результат целиком
  • Рассмотрите замену NOT IN на NOT EXISTS — последний не страдает от этой особенности

Вывод

Поведение NULL в SQL логично, если держать в голове концепцию трёхзначной логики. NULL — это не пустота, а неопределённость, и любое сравнение с ней даёт UNKNOWN. Зная это, достаточно добавить явную проверку IS NULL там, где NULL-значения должны оставаться в выборке.

Частые вопросы

Почему NOT IN с NULL возвращает пустой результат?+

Если список значений в NOT IN содержит хотя бы один NULL, SQL не может определить, входит ли проверяемое значение в список или нет. Каждое сравнение даёт UNKNOWN, и в итоге весь внешний запрос возвращает пустой результат.

Чем NOT EXISTS отличается от NOT IN при работе с NULL?+

NOT EXISTS проверяет наличие строк, а не совпадение значений, поэтому не подвержен проблеме с NULL. Если подзапрос возвращает строки с NULL, NOT EXISTS всё равно работает корректно, тогда как NOT IN даёт непредсказуемый результат.

Как проверить, что NULL не влияет на результаты моего запроса?+

Сравните COUNT(*) до и после фильтрации. Если разница больше ожидаемой, проверьте наличие NULL в задействованных столбцах с помощью WHERE column IS NULL.

Как правильно фильтровать данные, если нужно оставить строки с NULL?+

Добавьте явное условие: WHERE city NOT IN ('Москва') OR city IS NULL. Это гарантирует, что строки с NULL не будут молча отброшены фильтром.

319👍7
Читать оригинал в Telegram
Там можно оставить реакцию и написать комментарий
✈️ Открыть
🥰
Валерия Смирнова
Senior BI-аналитик в Авито · @mozzalerra
Сотрудничество →