NULL в SQL на собеседовании аналитика
Почему NULL — любимая ловушка интервьюеров
NULL в SQL — это не пустая строка, не ноль, не false. Это отсутствие значения. Последствия этого определения пронизывают весь язык: сравнения, агрегаты, JOIN, сортировку. Кандидаты, которые не понимают поведение NULL, делают ошибки в каждом втором запросе — и интервьюеры это знают.
NULL — самая коварная тема в SQL. Один забытый NULL может превратить корректный запрос в запрос, который молча возвращает неправильный результат.
Трёхзначная логика и IS NULL vs = NULL
В SQL любое сравнение с NULL возвращает не TRUE и не FALSE, а UNKNOWN. NULL = NULL — UNKNOWN. NULL != 1 — UNKNOWN. NULL > 0 — UNKNOWN. WHERE пропускает строки с UNKNOWN так же, как с FALSE.
Из этого следует ключевое правило: WHERE column = NULL не вернёт ни одной строки, даже если column содержит NULL. Правильно — WHERE column IS NULL. Аналогично, column != NULL не работает — нужен IS NOT NULL. На собеседовании интервьюер может показать запрос с = NULL и спросить, сколько строк он вернёт. Ответ — ноль, всегда.
NULL в агрегатных функциях
Поведение агрегатов с NULL — вторая по популярности тема.
COUNT(*) — считает все строки, включая те, где есть NULL. COUNT(column) — считает только строки, где column не NULL. Разница между ними — классический вопрос.
SUM, AVG, MIN, MAX — игнорируют NULL. Если в колонке значения 10, 20, NULL, то SUM = 30, AVG = 15 (не 10), MIN = 10, MAX = 20. NULL просто не участвует в расчёте.
Ловушка с AVG: если нужно учитывать NULL как ноль, необходимо использовать COALESCE(column, 0) внутри AVG. Без COALESCE среднее будет завышено, потому что NULL-строки не попадут в знаменатель.
COUNT(DISTINCT column) — тоже игнорирует NULL. Значения 'A', 'B', NULL, 'A' дадут COUNT(DISTINCT) = 2, а не 3.
Запомните: COUNT() считает строки, COUNT(column) считает значения. Если в столбце 100 строк и 20 из них NULL, COUNT() = 100, COUNT(column) = 80. Этот вопрос задают на каждом втором собеседовании.
NULL в JOIN и NOT IN
Строки с NULL в ключе JOIN никогда не соединятся, потому что NULL = NULL возвращает UNKNOWN. LEFT JOIN сохранит такие строки (с NULL в колонках правой таблицы), но INNER JOIN их отбросит.
Самая опасная ловушка — NOT IN с NULL. Запрос WHERE user_id NOT IN (SELECT user_id FROM banned_users) вернёт пустой результат, если в banned_users хотя бы одна строка с user_id = NULL. Сравнение с NULL даёт UNKNOWN, и всё выражение становится UNKNOWN. Решение — использовать NOT EXISTS вместо NOT IN или добавить IS NOT NULL в подзапрос.
COALESCE и NULLIF
COALESCE(a, b, c) — возвращает первое непустое значение из списка. Незаменим для замены NULL на значение по умолчанию: COALESCE(phone, email, 'нет контакта'). На собеседовании часто используется в задачах на объединение данных из нескольких источников.
NULLIF(a, b) — возвращает NULL, если a = b, иначе возвращает a. Классическое применение — защита от деления на ноль: revenue / NULLIF(orders_count, 0). Если orders_count = 0, NULLIF вернёт NULL, и результат деления будет NULL вместо ошибки.
Комбинация COALESCE и NULLIF — мощный инструмент: COALESCE(revenue / NULLIF(orders_count, 0), 0) — средний чек, который возвращает 0 вместо NULL при отсутствии заказов.
Типичные ошибки кандидатов
- Пишут
= NULLвместоIS NULL— запрос молча возвращает пустой результат. - Забывают про NULL в NOT IN — подзапрос с NULL обнуляет весь результат.
- Не учитывают NULL в AVG — среднее считается только по непустым значениям, что завышает результат.
- Забывают про NULL в конкатенации — в PostgreSQL
'Hello' || NULLвернёт NULL, не 'Hello'. - Не знают поведение DISTINCT с NULL — DISTINCT считает все NULL одним значением и оставляет одну строку.
Как готовиться
Возьмите за правило: каждый раз, когда пишете условие WHERE, спрашивайте себя — «а что, если здесь NULL?». Этот навык отличает опытного аналитика от начинающего. Пройдите все задачи на NULL в Карьернике — после 10-15 вопросов паттерны поведения NULL станут автоматическими.
Тема NULL тесно связана с GROUP BY и HAVING (агрегаты и NULL) и JOIN (NULL в ключах объединения). Все темы SQL-собеседований — в разделе вопросы по SQL.
FAQ
Почему NULL = NULL возвращает не TRUE?
Потому что NULL означает «значение неизвестно». Два неизвестных значения нельзя сравнить — мы не знаем, равны они или нет. Поэтому результат — UNKNOWN, а не TRUE и не FALSE. Это называется трёхзначная логика. Для проверки на NULL используйте IS NULL и IS NOT NULL.
Как обезопасить запрос от проблем с NULL?
Три правила: используйте IS NULL вместо = NULL, предпочитайте NOT EXISTS вместо NOT IN, и оборачивайте колонки в COALESCE, когда NULL может исказить результат. Также полезно проверять данные на наличие NULL перед написанием сложных запросов — это покажет интервьюеру, что вы думаете о качестве данных.
Что вернёт COUNT, если все значения в столбце — NULL?
COUNT(*) вернёт количество строк (не ноль, а реальное число строк). COUNT(column) вернёт 0, потому что ни одно значение не является не-NULL. SUM вернёт NULL (не 0). AVG тоже вернёт NULL. Это различие между COUNT и другими агрегатами часто проверяют на собеседованиях.