NULL в SQL означает «неизвестно», а не «пусто» — из-за этого строки с NULL молча выпадают из результата при использовании NOT IN. Разбираемся, почему это происходит и как это исправить.
Почему NULL — это «неизвестно», а не «пусто»
В SQL NULL не является пустой строкой или нулём. Это специальный маркер, который означает отсутствие известного значения. Из-за этого любое сравнение с NULL возвращает не TRUE и не FALSE, а третье логическое состояние — UNKNOWN.
Именно здесь кроется ловушка: в результирующий набор попадают только те строки, для которых условие WHERE вернуло TRUE. Строки с UNKNOWN — то есть строки, где значение равно NULL, — тихо отфильтровываются.
Как ведёт себя NOT IN при наличии NULL
Рассмотрим три сценария для условия city NOT IN ('Москва'):
- 'Москва' NOT IN ('Москва') → FALSE — строка не попадает в результат
- 'Питер' NOT IN ('Москва') → TRUE — строка попадает в результат
- NULL NOT IN ('Москва') → UNKNOWN — строка не попадает в результат
Таким образом, если в колонке city есть строки со значением NULL, они будут потеряны — без ошибки и без предупреждения. Это классическая скрытая ошибка в аналитических запросах.
Как правильно обработать NULL в условии фильтрации
Чтобы строки с NULL не терялись, нужно явно обработать этот случай через дополнительное условие OR:
- WHERE city NOT IN ('Москва') OR city IS NULL
Конструкция IS NULL явно возвращает TRUE для строк с неизвестным значением, поэтому они включаются в результат. Заметьте: проверять NULL через = NULL или != NULL бессмысленно — оба выражения вернут UNKNOWN.
Что сделать на практике
- При написании NOT IN всегда спрашивайте себя: могут ли в этой колонке быть NULL?
- Если да — добавляйте OR <column> IS NULL к условию фильтрации.
- Альтернатива — использовать NOT EXISTS или LEFT JOIN / IS NULL, которые ведут себя предсказуемо при наличии NULL.
- При ревью SQL-запросов коллег обращайте внимание на NOT IN с колонками, допускающими NULL — это частый источник тихих багов в отчётах.
Вывод
NOT IN с NULL — одна из самых коварных ловушек SQL именно потому, что она не вызывает ошибки. Результат просто оказывается неполным, а найти причину без знания трёхзначной логики SQL бывает непросто. Зная правило «NULL = UNKNOWN», эту ошибку легко предотвратить.