← Назад к вопросам

Как обрабатывать NULL значения в SQL? Приведите примеры с COALESCE, NULLIF, IS NULL.?

1.0 Junior🔥 171 комментариев
#SQL и базы данных

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Обработка NULL значений в SQL

NULL в SQL — это отсутствие значения, отличается от пуста строки или нуля. Правильная работа с NULL критична для точных аналитических отчётов.

Основная проблема NULL

-- NULL уникален: любое сравнение с NULL дает NULL, не TRUE или FALSE
SELECT NULL = NULL;      -- результат: NULL (не TRUE!)
SELECT NULL <> 5;        -- результат: NULL
SELECT 10 + NULL;        -- результат: NULL
SELECT NULL || 'text';   -- результат: NULL

Поэтому для работы с NULL используются специальные функции.

1. IS NULL и IS NOT NULL

Единственный способ правильно проверить NULL:

-- Найти все заказы без рефертуры скидочного кода
SELECT order_id, total_amount
FROM orders
WHERE discount_code IS NULL;

-- Найти пользователей с заполненным email
SELECT user_id, name, email
FROM users
WHERE email IS NOT NULL;

-- Комбинирование условий
SELECT user_id, name, last_purchase_date
FROM users
WHERE 
  last_purchase_date IS NOT NULL
  AND last_purchase_date > '2024-01-01';

2. COALESCE() — заменить NULL на значение

Возвращает первый НЕ-NULL аргумент:

-- Заменить NULL на 0
SELECT user_id, COALESCE(lifetime_value, 0) as ltv
FROM users;

-- Множественные fallbacks
SELECT 
  user_id,
  COALESCE(
    preferred_email,      -- используй основной email
    secondary_email,      -- или вспомогательный
    'no-email@example.com' -- или дефолт
  ) as contact_email
FROM users;

-- Практический пример: заполнение данных
SELECT
  user_id,
  COALESCE(
    phone_country_code,
    country_code,
    'US'
  ) as country
FROM users;

Когда использовать COALESCE:

  • Замена NULL на дефолтное значение для отчёта
  • Заполнение отсутствующих данных из альтернативных источников
  • Подготовка данных к экспорту (некоторые системы не поддерживают NULL)

3. NULLIF() — превратить значение в NULL

Обратное COALESCE — возвращает NULL, если аргументы равны:

-- Пример: показать изменение цены, NULL если цена не изменилась
SELECT
  product_id,
  old_price,
  new_price,
  NULLIF(new_price - old_price, 0) as price_change
FROM price_history;

-- Результат:
-- product_id | old_price | new_price | price_change
--    101     |    50     |    55     |      5
--    102     |    40     |    40     |     NULL  ← не изменилась
--    103     |    80     |    75     |     -5

Практическое применение:

-- Избежать деления на 0 (которое выдаёт ошибку или бесконечность)
SELECT
  product_id,
  impressions,
  clicks,
  CASE 
    WHEN impressions = 0 THEN NULL  -- или можно использовать NULLIF
    ELSE clicks::FLOAT / impressions
  END as ctr
FROM ad_metrics;

-- Или более элегантно с NULLIF
SELECT
  product_id,
  impressions,
  clicks,
  clicks::FLOAT / NULLIF(impressions, 0) as ctr
FROM ad_metrics;

4. Комбинированные примеры

Пример 1: Анализ обработки заказов

-- Найти заказы, где не заполнена дата доставки
-- (в обработке или потеряны)
SELECT
  order_id,
  user_id,
  created_at,
  CASE 
    WHEN delivered_at IS NULL THEN 'pending'
    ELSE 'delivered'
  END as order_status,
  -- Дни в доставке (NULL если ещё не доставлен)
  NULLIF(
    EXTRACT(DAY FROM delivered_at - created_at),
    0
  ) as days_to_deliver
FROM orders
WHERE created_at > NOW() - INTERVAL '30 days';

Пример 2: Объединение данных из двух источников

-- У пользователя есть данные в двух таблицах
-- Используем COALESCE для приоритета источников
SELECT
  COALESCE(u.user_id, up.user_id) as user_id,
  COALESCE(u.email, up.email) as email,
  COALESCE(u.country, up.country, 'Unknown') as country,
  u.premium_status,
  up.profile_completed
FROM users u
FULL OUTER JOIN user_profiles up ON u.user_id = up.user_id;

Пример 3: Выявление пропущенных данных

-- Report о качестве данных
SELECT
  'email_missing' as data_quality_issue,
  COUNT(*) as affected_rows,
  ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM users), 2) as pct_of_total
FROM users
WHERE email IS NULL
UNION ALL
SELECT
  'phone_missing',
  COUNT(*),
  ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM users), 2)
FROM users
WHERE phone IS NULL
UNION ALL
SELECT
  'both_missing',
  COUNT(*),
  ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM users), 2)
FROM users
WHERE email IS NULL AND phone IS NULL;

Пример 4: Агрегирующие функции и NULL

-- Важно: SUM, AVG, COUNT игнорируют NULL
SELECT
  user_id,
  COUNT(*) as total_purchases,              -- считает все строки
  COUNT(coupon_code) as purchases_with_coupon, -- считает только не-NULL
  SUM(amount) as total_spent,                  -- NULL в сумме игнорируется
  AVG(amount) as avg_purchase,                 -- NULL в среднем игнорируется
  COALESCE(AVG(amount), 0) as avg_or_zero
FROM purchases
GROUP BY user_id;

-- Результат:
-- user_id | total_purchases | purchases_with_coupon | total_spent | avg_purchase | avg_or_zero
--    1    |        5        |          2            |    500      |    100       |     100
--    2    |        3        |          0            |    100      |     33.33    |    33.33

5. IFNULL vs COALESCE (разные БД)

-- MySQL: IFNULL(column, replacement)
SELECT IFNULL(discount, 0) as discount FROM orders;

-- SQL Server: ISNULL(column, replacement)
SELECT ISNULL(discount, 0) as discount FROM orders;

-- PostgreSQL, SQLite, BigQuery: COALESCE
SELECT COALESCE(discount, 0) as discount FROM orders;

6. NULL в ORDER BY

-- NULL обычно сортируется в начало или в конец (зависит от БД)
SELECT user_id, premium_expiry
FROM users
ORDER BY premium_expiry DESC NULLS LAST;  -- NULL в конце

-- PostgreSQL: NULLS FIRST / NULLS LAST
-- MySQL: просто ORDER BY (NULL идет в начало)
-- SQLite: NULL идет в начало при DESC, в конец при ASC

7. Проверка NULL в JOIN

-- ВНИМАНИЕ: NULL = NULL это NULL, не TRUE!
-- Неправильно:
SELECT u.user_id, o.order_id
FROM users u
JOIN orders o ON u.referral_code = o.referral_code;
-- Пропустит все пары, где оба NULL!

-- Правильно:
SELECT u.user_id, o.order_id
FROM users u
JOIN orders o ON u.referral_code = o.referral_code
UNION ALL
SELECT u.user_id, o.order_id
FROM users u
JOIN orders o ON u.referral_code IS NULL AND o.referral_code IS NULL;

Чеклист работы с NULL

  • ☑ Используй IS NULL / IS NOT NULL, не = NULL
  • ☑ COALESCE для замены NULL на значение
  • ☑ NULLIF для превращения значения в NULL
  • ☑ Помни: SUM, AVG, COUNT игнорируют NULL
  • ☑ Проверяй COUNT(*) vs COUNT(column_with_nulls) — разные результаты
  • ☑ JOIN не работает с NULL — нужна отдельная логика
  • ☑ Документируй, какие NULL в твоих таблицах — отсутствующие данные или явное "нет"
  • ☑ При GROUP BY NULL = NULL, поэтому NULL-ы группируются вместе

Лучшие практики

  1. Минимизируй NULL — если возможно, используй дефолтные значения при создании таблиц

    CREATE TABLE users (
      user_id BIGINT,
      email VARCHAR NOT NULL,
      phone VARCHAR DEFAULT '',  -- вместо NULL
      premium BOOLEAN DEFAULT FALSE
    );
    
  2. Документируй NULL — что означает NULL в каждой колонке?

    • NULL = отсутствующие данные, не заполнено еще
    • NULL = явное "не применимо" для этого пользователя
  3. Тестируй граничные случаи — включай NULL в тестах

  4. Используй правильно в CASE — NULL может быть результатом

    CASE 
      WHEN column IS NULL THEN 'missing'
      WHEN column = 0 THEN 'zero'
      ELSE 'has value'
    END
    
Как обрабатывать NULL значения в SQL? Приведите примеры с COALESCE, NULLIF, IS NULL.? | PrepBro