SQLLab

NULL в SQL: как работать с отсутствующими данными

NULL — отсутствие значения. Не ноль, не пустая строка — именно отсутствие. NULL ведёт себя неожиданно: NULL = NULL → false, NULL + 5 → NULL. Понимание NULL обязательно на любом SQL-собеседовании.

NULL — это не значение

NULL означает «неизвестно» или «не применимо». Поэтому: - NULL = NULL → не TRUE, а NULL (неизвестно, равны ли два неизвестных) - NULL != NULL → тоже NULL - Любая арифметика с NULL → NULL - Любое сравнение с NULL → NULL (не TRUE, не FALSE)

Для проверки на NULL используй IS NULL или IS NOT NULL — никогда = NULL.

Проверка на NULL
-- Неправильно: = NULL всегда возвращает NULL (не TRUE)
SELECT * FROM users WHERE phone = NULL;   -- вернёт 0 строк!

-- Правильно:
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;

NULL в агрегатных функциях

COUNT(*) — считает все строки включая NULL. COUNT(col) — считает только строки, где col не NULL. SUM, AVG, MAX, MIN — игнорируют NULL.

AVG(col) = SUM(col) / COUNT(col) — то есть NULL строки не учитываются в среднем. Это часто удивляет.

Агрегатные функции и NULL
SELECT
  COUNT(*)        AS total_rows,     -- все строки
  COUNT(phone)    AS with_phone,     -- только не-NULL
  AVG(rating)     AS avg_rating,     -- NULL игнорируются
  SUM(bonus)      AS total_bonus     -- NULL = 0 в сумме
FROM users;

COALESCE — подстановка значения по умолчанию

COALESCE(a, b, c, ...) возвращает первый не-NULL аргумент. Идеально для замены NULL на значение по умолчанию.

COALESCE: первое не-NULL значение
-- Если bonus NULL — считаем как 0
SELECT
  name,
  salary + COALESCE(bonus, 0) AS total_compensation
FROM employees;

-- Цепочка: попробовать mobile, потом home, потом 'Нет телефона'
SELECT COALESCE(mobile_phone, home_phone, 'Нет телефона') AS contact
FROM users;

NULLIF — вернуть NULL при совпадении

NULLIF(a, b) возвращает NULL если a = b, иначе возвращает a. Главное применение — защита от деления на ноль.

NULLIF: защита от деления на ноль
-- Защита от деления на ноль
SELECT
  total_revenue / NULLIF(total_orders, 0) AS avg_order
FROM stats;
-- Если total_orders = 0 → NULLIF вернёт NULL → деление на NULL = NULL
-- Вместо ERROR: division by zero

NULL в JOIN и NOT IN

NULL в JOIN: строки с NULL в колонке джойна никогда не совпадут — ни с чем, даже с другим NULL. Нужен LEFT JOIN + IS NULL если хочешь их поймать.

NULL в NOT IN — самая опасная ловушка. Если подзапрос вернул хоть один NULL — NOT IN вернёт 0 строк.

NOT IN с NULL — классическая ловушка
-- Опасно: если в подзапросе есть NULL — результат пустой
SELECT * FROM orders
WHERE user_id NOT IN (SELECT manager_id FROM departments);
-- manager_id может быть NULL → NOT IN не работает как ожидается

-- Безопасно: NOT EXISTS
SELECT * FROM orders o
WHERE NOT EXISTS (
  SELECT 1 FROM departments d WHERE d.manager_id = o.user_id
);

Закрепи знания на практике

Решай реальные задачи с собеседований прямо в браузере — без установки.

Решить задачи с NULL