SQLNULLIFNULLtutorial

Что такое NULLIF в SQL? Безопасное деление и очистка для начинающих

NULLIF — это «верни NULL, если два значения равны». Простыми словами: безопасное деление через NULLIF(x, 0), очистка плейсхолдеров типа '' или 'unknown', связка с COALESCE для аккуратной обработки данных. С таблицами и частыми ошибками.

3 мин чтенияСправочникSQL · NULLIF · NULL · tutorial

NULLIF — это функция «если два значения равны — верни NULL, иначе — первое». На первый взгляд звучит странно (зачем нам специально делать NULL?). Но на практике это идеальный инструмент для двух задач:

  1. Безопасное деление — превратить «возможный 0 в знаменателе» в NULL, чтобы не было ошибки.
  2. Очистка плейсхолдеров — превратить '', 'unknown', 0, -1 (всё что используют как «нет данных») в нормальный NULL.

NULLIF — антипод COALESCE: одна функция убирает NULL'ы, вторая — создаёт их там, где это удобнее.

Зачем нужен NULLIF

Главный случай — деление без падения запроса:

-- Если count = 0, упадёт с division by zero
SELECT total / count FROM stats;

NULLIF(count, 0) превратит 0 в NULL. А деление на NULL в Postgres даёт NULL (не ошибку):

SELECT total / NULLIF(count, 0) FROM stats;
-- → если count = 0, результат NULL, без ошибки
-- → если count = 7, результат 17 / 7 = 2.43

Дальше можно обернуть в COALESCE если хочешь «0 при пусто»:

SELECT COALESCE(total / NULLIF(count, 0), 0) FROM stats;

Базовый синтаксис

NULLIF(значение1, значение2)
  • Если значение1 = значение2 — возвращает NULL.
  • Иначе — возвращает значение1.
SELECT NULLIF(5, 5);   -- NULL
SELECT NULLIF(5, 0);   -- 5
SELECT NULLIF('', '');  -- NULL
SELECT NULLIF('a', 'b'); -- 'a'

Очистка плейсхолдеров

В реальных данных часто встречаются «псевдо-NULL» — значения, которые формально не NULL, но смысл у них такой же:

  • '' (пустая строка вместо «нет email»)
  • 'unknown', 'N/A', '-' (текстовые плейсхолдеры)
  • 0, -1 (числовые плейсхолдеры для «не указано»)

NULLIF превращает их в настоящий NULL:

-- Превратить пустые строки в NULL
SELECT name, NULLIF(email, '') AS email_clean
FROM users;

-- Превратить -1 в NULL для возраста
SELECT name, NULLIF(age, -1) AS age_clean
FROM users;

После такой очистки агрегаты, IS NULL-проверки и COUNT(column) работают «правильно» — они умеют обращаться с NULL'ами, а с плейсхолдерами надо помнить про каждый фильтр отдельно.

Пример с таблицей

Таблица forms:

id name phone email
1 Аня +79991234567
2 Боб bob@example.com
3 Вера +79992223344 vera@example.com

COUNT(email) нам не покажет «у скольки заполнен email» — потому что '' это валидное значение, не NULL.

-- "Сколько строк с email" — но '' тоже считается
SELECT COUNT(email) FROM forms;  -- 3 (даже у Ани, у которой email = '')

-- Чисто — превращаем '' в NULL, COUNT отфильтрует
SELECT COUNT(NULLIF(email, '')) FROM forms;  -- 2

То же для phone:

SELECT COUNT(NULLIF(phone, '')) AS users_with_phone FROM forms;

NULLIF + COALESCE — мощная пара

Когда хочешь обработать «и NULL, и пустые», и поставить дефолт — комбо:

SELECT
  COALESCE(NULLIF(nickname, ''), full_name, 'Гость') AS display_name
FROM users;

Логика:

  1. Если nickname = ''NULLIF превратит в NULL.
  2. COALESCE пойдёт дальше: возьмёт full_name если есть.
  3. Если и full_name пустой/NULL (потребуется ещё один NULLIF, если full_name тоже может быть '') — поставит 'Гость'.

Безопасный CTR (click-through rate)

Реалистичный пример — расчёт CTR (отношение кликов к показам):

SELECT
  campaign_id,
  ROUND(100.0 * clicks / NULLIF(impressions, 0), 2) AS ctr_percent
FROM ad_stats;

Если у кампании 0 показов — NULLIF(impressions, 0)NULL, и весь ctrNULL. Без ошибки. Без NULLIF запрос упадёт на первой кампании без impressions.

Частые ошибки новичков

1. Забывают, что NULLIF сравнивает только на полное равенство. NULLIF(' ', '') НЕ превратит «пробел» в NULL — это разные строки. Если хочешь нормализовать пробелы, сначала TRIM:

NULLIF(TRIM(value), '')

2. NULLIF с числами и строками — типы. NULLIF(age, '0') — Postgres попробует сравнить число и строку. Лучше — оба числа: NULLIF(age, 0).

3. Деление без NULLIF. SELECT total / count пройдёт первые 1000 раз, на 1001-м клиенте с count = 0 упадёт. Привычка: любое деление, где знаменатель не гарантированно > 0 — оборачивай в NULLIF(divisor, 0).

4. Думают, что NULLIF(NULL, NULL) вернёт NULL. Технически да, но это бесполезно. NULLIF(x, x) всегда вернёт NULL, потому что NULL = NULL в SQL даёт NULL (не TRUE), и логика «если равны → NULL» не сработает на двух NULL'ах. На практике это никогда не нужно.

5. Использовать NULLIF в WHERE для проверки «не плейсхолдер». Можно, но обычно длиннее, чем нужно:

-- Длинно
WHERE NULLIF(email, '') IS NOT NULL

-- Короче
WHERE email IS NOT NULL AND email <> ''

-- Или совсем коротко при отсутствии NULL'ов
WHERE email <> ''

NULLIF блестит в SELECT и арифметике, не в WHERE.

Мини-резюме

  • NULLIF(a, b) возвращает NULL, если a = b. Иначе — a.
  • Главное применение — безопасное деление: total / NULLIF(count, 0).
  • Очистка плейсхолдеров: NULLIF(value, ''), NULLIF(age, -1).
  • В паре с COALESCE — мощный fallback с защитой от пустых строк.
  • Сравнивает только на полное равенство — для нормализации пробелов сначала TRIM.

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

Решай задачи в SQL-тренажёре с мгновенной проверкой и подсказками.

Открыть тренажёр