Работа с NULL
NULL означает «значение отсутствует», то есть «неизвестно», и не совпадает ни с нулём, ни с пустой строкой, ни с false. Игнорировать его нельзя, потому что арифметика и сравнения обходятся с ним по особым правилам.
Главное правило
Заголовок раздела «Главное правило»Любая операция с NULL даёт NULL. Если хотя бы один из аргументов отсутствует — результат тоже отсутствует.
1 + null -- nullgrade * 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
Заголовок раздела «Замена пропуска: COALESCE»coalesce возвращает первый не-NULL аргумент. Если все NULL — вернёт NULL.
coalesce(density, 2.7) -- если density не задан, взять 2.7coalesce(grade_au, grade_ag, 0) -- сначала золото, потом серебро, потом 0Главное применение — защита арифметики. Одна незаполненная колонка иначе обнуляет всю формулу.
grade * tonnage * recovery -- любой пропуск -> NULLcoalesce(grade, 0) * tonnage * coalesce(recovery, 1) -- защищеноЗначение по умолчанию выбирается по смыслу: для содержания это 0, для извлечения — 1, для объёмного веса — среднее по типу породы.
Тот же приём убирает потерю строк в фильтре:
coalesce(grade, 0) <= 0.5 -- пропуск считается нулём и попадёт в отбор