Перейти к содержимому

Работа с NULL

NULL означает «значение отсутствует», то есть «неизвестно», и не совпадает ни с нулём, ни с пустой строкой, ни с false. Игнорировать его нельзя, потому что арифметика и сравнения обходятся с ним по особым правилам.

Любая операция с NULL даёт NULL. Если хотя бы один из аргументов отсутствует — результат тоже отсутствует.

1 + null -- null
grade * tonnage -- null, если хотя бы одна из колонок null в этой строке

Сравнение — тоже операция, поэтому grade > 0.5 для пропуска даёт не «ложь», а NULL. Условие не выполнено, но и не нарушено — «неизвестно».

Из-за этого чаще всего и получают неверный результат:

  • Фильтр молча теряет строки. grade <= 0.5 не оставит блоки с пропуском, и ошибки при этом не будет — просто строк станет меньше
  • Ветка case when не срабатывает. when grade > 0.5 then 'ore' для пропуска пропускается, и блок уходит в else

Сравнить с NULL через = нельзя, grade = null не вернёт ни одной строки. Для проверки есть отдельная запись:

grade is null -- истина для отсутствующих значений
grade is not null -- истина для заполненных

Фильтр «всё кроме вскрыши, включая блоки без классификации»:

rock <> 'waste' or rock is null

Чтобы блоки с пропуском не уходили в else, для них добавляется отдельная ветка:

case
when grade is null then 'unknown'
when grade > 0.5 then 'ore'
else 'waste'
end

coalesce возвращает первый не-NULL аргумент. Если все NULL — вернёт NULL.

coalesce(density, 2.7) -- если density не задан, взять 2.7
coalesce(grade_au, grade_ag, 0) -- сначала золото, потом серебро, потом 0

Главное применение — защита арифметики. Одна незаполненная колонка иначе обнуляет всю формулу.

grade * tonnage * recovery -- любой пропуск -> NULL
coalesce(grade, 0) * tonnage * coalesce(recovery, 1) -- защищено

Значение по умолчанию выбирается по смыслу: для содержания это 0, для извлечения — 1, для объёмного веса — среднее по типу породы.

Тот же приём убирает потерю строк в фильтре:

coalesce(grade, 0) <= 0.5 -- пропуск считается нулём и попадёт в отбор