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 и другими агрегатами часто проверяют на собеседованиях.

Смотрите также