При работе с запросами в системе 1С:Предприятие начинающие разработчики часто сталкиваются с типом NULL. Возникает закономерный вопрос: нужно ли всегда избавляться от него, используя функцию ЕСТЬNULL, или можно оставить данные «как есть»? В этой статье мы подробно разберем природу этого типа, выясним, почему обычное сравнение с ним не работает, и проанализируем лучшие практики его обработки.
Прежде всего, давайте определим, что NULL — это не ноль, не пустая строка и даже не Неопределено. Это специальный маркер, обозначающий полное отсутствие данных. В запросах 1С NULL чаще всего появляется в результате Левого или Полного соединения таблиц, когда для записи из левой таблицы не находится соответствующей записи в правой таблице.
Рассмотрим ситуацию на примере. Допустим, мы соединяем таблицу «Продажи» с таблицей «Скидки» по полю Номенклатура. Если на какой-то товар скидка не установлена, в колонке со значением скидки мы получим NULL. Проанализируем, к чему это приведет при дальнейших расчетах.
Самая распространенная ошибка — попытка сравнить NULL с чем-либо (даже с другим NULL) с помощью обычного оператора равенства. Проанализируем логику СУБД: выражение NULL = NULL вернет не ИСТИНА, а UNKNOWN (неизвестно), что в условиях фильтрации ГДЕ ведет себя аналогично значению ЛОЖЬ.
Если нам нужно проверить поле на наличие этого значения, мы должны использовать специальную конструкцию:
ГДЕ
Таблица.Поле ЕСТЬ NULL
Или наоборот, если мы хотим исключить пустые связи:
ГДЕ
НЕ Таблица.Поле ЕСТЬ NULL
Разберем подробнее, как работают логические операции, когда в них замешан NULL. Это критично для понимания того, как будет вести себя ваш запрос:
ЛОЖЬ, если хотя бы один операнд ЛОЖЬ. Но если один операнд ИСТИНА, а второй NULL, результат будет NULL.ИСТИНА, результат будет ИСТИНА. Если же один ЛОЖЬ, а второй NULL, результат будет NULL.NULL всегда возвращает NULL.Для замены «пустоты» на конкретное значение используется функция ЕСТЬNULL(Поле, ЗначениеЗамены). Посмотрим на пример обработки числовых данных:
ВЫБРАТЬ
Продажи.Номенклатура,
ЕСТЬNULL(Продажи.Количество, 0) КАК Количество
ИЗ
РегистрНакопления.Продажи КАК Продажи
Важно помнить о приведении типов при использовании этой функции. ЕСТЬNULL ограничивает тип результата типом первого аргумента. Если Поле имеет тип Строка(10), а в качестве замены вы укажете строку длиной 20 символов, то значение будет обрезано до 10 символов. Рассмотрим ситуацию, когда ЕСТЬNULL работает быстрее, чем конструкция ВЫБОР КОГДА ... ТОГДА, так как она транслируется напрямую в нативную функцию СУБД.
Выясним причину, почему математические операции с NULL могут «сломать» ваш отчет. Любая операция сложения, вычитания или конкатенации строк с участием NULL дает NULL.
Например: 100 + NULL = NULL. Если в вашем запросе вы суммируете показатели из разных таблиц, обязательно оборачивайте их в ЕСТЬNULL, иначе отсутствие данных в одной колонке обнулит всю строку.
С агрегатными функциями ситуация иная:
СУММА, СРЕДНЕЕ, МИНИМУМ — игнорируют NULL. Они рассчитывают результат только по тем строкам, где значения заполнены.КОЛИЧЕСТВО(Поле) — посчитает только непустые значения.КОЛИЧЕСТВО(*) — посчитает все строки, даже если они целиком состоят из NULL.Проанализируем вопрос производительности. Использование функции ЕСТЬNULL в секции ГДЕ может существенно замедлить запрос. Это происходит потому, что СУБД не может эффективно использовать индексы по полю, обернутому в функцию (запрос становится non-SARGable).
Плохой вариант:
ГДЕ
ЕСТЬNULL(СуммаОстаток, 0) > 100
В этом случае СУБД придется выполнить сканирование всей таблицы (Full Table Scan).
Хороший вариант:
ГДЕ
СуммаОстаток > 100
ИЛИ СуммаОстаток ЕСТЬ NULL
Такой подход позволяет оптимизатору использовать индекс по полю СуммаОстаток.
Часто возникает путаница между этими понятиями. Проанализируем отличия:
Неопределено — это физическое значение, которое может храниться в базе данных (например, в поле составного типа). Оно имеет свой внутренний код типа.NULL — это отсутствие значения в принципе. В таблицах 1С оно не хранится как значение поля (за исключением редких случаев в SQL-таблицах), а возникает «на лету» в процессе выполнения запросов.Подведем итог. Убирать NULL из запроса нужно в следующих случаях:
Однако, иногда NULL полезен. Например, когда вам нужно найти записи, для которых нет соответствия в другой таблице. В этом случае мы специально ищем NULL, чтобы понять, какие данные отсутствуют.