Как NULL ведёт себя в сравнениях, агрегатах и JOIN?
Короткий ответ
NULL — это «неизвестно», а не ноль и не пустая строка. Любое сравнение с NULL даёт не TRUE/FALSE, а UNKNOWN, поэтому проверяют через IS NULL, а не = NULL. Агрегаты (кроме count(*)) пропускают NULL. В JOIN строки с NULL в ключе не совпадают друг с другом. В WHERE UNKNOWN отсекает строку.
NULL — не значение, а его отсутствие. Один этот сдвиг в голове снимает половину «необъяснимых» багов в отчётах, где строки таинственно пропадают или суммы не сходятся.
Как рассуждать
Замени в уме слово NULL на «неизвестно» и перечитай запрос. length > 100, если длина неизвестна, — это «неизвестно > 100», то есть неизвестно. Не TRUE и не FALSE, а третье состояние — UNKNOWN. Отсюда трёхзначная логика.
Дальше всё выводится:
- Сравнение с NULL всегда UNKNOWN, поэтому
x = NULLне работает — толькоIS NULL. - WHERE пропускает строку, только если условие TRUE. UNKNOWN — не TRUE, значит строка отваливается.
- Агрегаты
sum/avg/count(col)игнорируют NULL, аcount(*)считает строки целиком. - В JOIN два NULL не равны друг другу — пары не будет.
Эталонный ответ
NULL означает «значение неизвестно». Ключевые следствия по областям.
Сравнения. NULL = NULL даёт не TRUE, а UNKNOWN. Поэтому проверка на пропуск — только IS NULL / IS NOT NULL:
SELECT count(*) FROM rental WHERE return_date IS NULL; -- не возвращённые: 183
Агрегаты. avg(col) делит сумму на число НЕпустых значений, а не на все строки. Если считаешь среднее и часть значений NULL — среднее будет по имеющимся. count(return_date) посчитает только возвраты, count(*) — все аренды. Расхождение этих двух чисел — как раз количество NULL.
JOIN. Строки, где ключ соединения NULL, не склеятся: условие a.key = b.key при NULL — UNKNOWN. Поэтому нельзя джойнить по «пустым» полям в надежде, что «пусто совпадёт с пусто».
CASE и фильтры. NOT IN (подзапрос со NULL) — коварная штука: один NULL в списке делает весь результат UNKNOWN, и запрос молча возвращает пусто. Лечится NOT EXISTS или отсевом NULL в подзапросе.
Сильный ответ добавит про инструменты нормализации: COALESCE(x, 0) подставит значение вместо NULL (например, чтобы фильмы без аренд считались с нулевой выручкой), а NULLIF(a, b) вернёт NULL при равенстве — классика для защиты от деления на ноль.
Частые ошибки
- Пишут
WHERE col = NULLи не понимают, почему пусто. ТолькоIS NULL. - Думают, что NULL — это 0 или ''. Ноль участвует в арифметике, а
NULL + 5= NULL. - Забывают ловушку
NOT INсо NULL: результат схлопывается в пусто без единой ошибки. - Ждут, что NULL совпадёт при соединении, и теряют строки. Это же — причина сюрпризов при фильтре правой таблицы после LEFT JOIN.
- Путают
count(*)иcount(col)при подсчёте — и получают разные числа, не понимая, что виноваты пропуски.
Потренируй этот вопрос с ИИ-интервьюером
Читать разбор полезно, а отвечать вслух под давлением — совсем другое. ИИ-интервьюер задаст этот и смежные вопросы, будет копать глубже и разберёт твои ответы. Первое короткое интервью — бесплатно.
Пройти собеседование бесплатно