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 (не 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 строки не учитываются в среднем. Это часто удивляет.
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 на значение по умолчанию.
-- Если 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. Главное применение — защита от деления на ноль.
-- Защита от деления на ноль
SELECT
total_revenue / NULLIF(total_orders, 0) AS avg_order
FROM stats;
-- Если total_orders = 0 → NULLIF вернёт NULL → деление на NULL = NULL
-- Вместо ERROR: division by zeroNULL в JOIN и NOT IN
NULL в JOIN: строки с NULL в колонке джойна никогда не совпадут — ни с чем, даже с другим NULL. Нужен LEFT JOIN + IS NULL если хочешь их поймать.
NULL в NOT IN — самая опасная ловушка. Если подзапрос вернул хоть один NULL — NOT IN вернёт 0 строк.
-- Опасно: если в подзапросе есть 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 →