NULL и трёхзначная логика

↑ 1.1 Реляционная модель и SQL · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: junior

Зачем это на собесе

NULL — источник самых неочевидных ошибок; на нём строят каверзные вопросы.

Что такое NULL

Отсутствие значения / неизвестное значение, а не ноль и не пустая строка. Любое сравнение с NULL даёт UNKNOWN.

Трёхзначная логика

ABA AND BA OR B
TRUEUNKNOWNUNKNOWNTRUE
FALSEUNKNOWNFALSEUNKNOWN
UNKNOWNUNKNOWNUNKNOWNUNKNOWN

NOT UNKNOWN — UNKNOWN. WHERE пропускает только TRUE, строки с UNKNOWN отбрасываются.

SELECT NULL = NULL;        -- NULL (не true)
SELECT NULL IS NULL;       -- true
SELECT 1 = NULL;           -- NULL
SELECT NULL IS DISTINCT FROM NULL;   -- false (NULL-безопасное сравнение)

Правила

  • проверка: IS NULL / IS NOT NULL, а не = NULL;
  • x <> 5 не вернёт строки, где x IS NULL; нужно x IS DISTINCT FROM 5;
  • NOT IN с NULL в списке — пустой результат; используйте NOT EXISTS;
  • арифметика и конкатенация с NULL дают NULL ('a' || NULL → NULL, функция concat игнорирует NULL);
  • агрегаты (sum, avg, count(col)) игнорируют NULL; count(*) — нет;
  • ORDER BY: NULL считаются больше любого значения (NULLS LAST по умолчанию при ASC);
  • GROUP BY, DISTINCT, UNION считают NULL равными между собой;
  • UNIQUE допускает несколько NULL (можно отключить через NULLS NOT DISTINCT, PostgreSQL 15+);
  • CHECK пропускает NULL (UNKNOWN не нарушает ограничение): ставьте NOT NULL.

Функции

coalesce(a, b, 'по умолчанию')   -- первое не-NULL
nullif(a, 0)                     -- NULL, если a = 0 (защита от деления на ноль: x / nullif(y, 0))
a IS DISTINCT FROM b

Когда NULL допустим

Реально «неизвестно» или «неприменимо» (дата закрытия у открытого тикета). Избегайте NULL для флагов (используйте boolean NOT NULL DEFAULT false) и там, где есть осмысленное значение по умолчанию.

Индексы

B-tree индексирует NULL (можно искать IS NULL). Частичный индекс WHERE deleted_at IS NULL — частый приём.

Вопросы с ответами