К статье
Практический материал

Разработка и Конфигурация · 11 мин

NULL как 0 в 1С: как правильно обработать пустые значения

Как в 1С заменить NULL на 0 в запросах: функция ЕСТЬNULL, левые соединения, итоги, СКД и вычисляемые поля. Примеры кода, типичные ошибки и проверка результата.

Запрос в 1С вернул пустую колонку вместо нулей, отчёт «потерял» строки, а при сложении остатка с продажами результат внезапно стал пустым — почти всегда причина одна: значение NULL. NULL в запросах 1С означает отсутствие значения, а не ноль, поэтому любая арифметическая операция с NULL даёт NULL, а сравнение NULL с числом не даёт ни ИСТИНА, ни ЛОЖЬ.

Чаще всего NULL появляется при левом соединении таблиц, когда в правой таблице нет подходящей записи: например, у номенклатуры нет остатка на складе или нет продаж за период. Также NULL возникает в итогах по группировкам и при обращении к реквизиту через точку, если ссылка битая или значение не заполнено на уровне составного типа.

Стандартный способ привести NULL к нулю — функция ЕСТЬNULL(Выражение, 0). Но у неё есть нюансы с типами, местами применения и влиянием на производительность. Ниже разобраны все практические сценарии: от простого запроса до СКД и виртуальных таблиц.

Чем NULL отличается от нуля и почему это ломает отчёты

NULL — специальный маркер «значение отсутствует». Число 0 — вполне определённое значение, с которым можно считать. Различие критично в трёх местах: арифметика, сравнения и агрегатные функции.

В арифметике любое действие с NULL возвращает NULL: NULL + 5 даст NULL, а не 5. Именно поэтому формула вида Остаток + Приход - Расход «молча» обнуляет строку, если одно из полей пришло из левого соединения без совпадения.

В сравнениях NULL не равен ничему, включая сам себя. Условие ГДЕ Остаток = 0 не отберёт строки с NULL, а условие ГДЕ Остаток <> 0 — тоже. Строки с NULL просто выпадают из выборки в обеих проверках, что выглядит как «пропавшие» данные.

Откуда берётся NULL: типовые источники

Первый и самый частый источник — левое соединение. Если соединить справочник «Номенклатура» с таблицей остатков и для части товаров остатков нет, поля из таблицы остатков будут NULL. То же происходит с полным соединением в обе стороны и с правым соединением.

Второй источник — обращение через точку к реквизитам ссылки: Документ.Контрагент.ИНН. Если ссылка битая (объект удалён без контроля ссылочной целостности) или поле составного типа содержит значение другого типа, результат — NULL.

Третий источник — группировки и итоги. При использовании «ОБЩИЕ» или группировочных наборов в полях, не входящих в группировку, появляется NULL. Также NULL может вернуть агрегатная функция, если набор строк пуст.

Пустая ячейка вместо числаВероятен NULL из соединения

Проверить, есть ли в запросе ЛЕВОЕ СОЕДИНЕНИЕ без ЕСТЬNULL

Строки пропали из результатаNULL в условии ГДЕ

Сравнение с NULL отсекает строку; нужна проверка ЕСТЬ NULL

Сумма строки пустаяNULL в арифметике

Одно из слагаемых NULL — обернуть поля в ЕСТЬNULL

Функция ЕСТЬNULL: синтаксис и правила применения

Функция принимает два аргумента: проверяемое выражение и значение, которое подставляется вместо NULL. Запись ЕСТЬNULL(Остатки.КоличествоОстаток, 0) вернёт остаток, а если его нет — ноль.

Оба аргумента должны быть совместимы по типу. Если первый аргумент числовой, второй тоже должен быть числом — подставить строку «нет данных» в числовое поле не получится без приведения типов. Для дат корректная замена — ДАТАВРЕМЯ(1,1,1), для строк — пустая строка, для ссылок — пустая ссылка через ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка).

ЕСТЬNULL работает только с одним уровнем вложенности: если NULL пришёл из соединения, функция его заменит, но если NULL вложен в более сложное выражение (например, ЕСТЬNULL(А, 0) + Б, где Б тоже может быть NULL), обрабатывать нужно каждое поле отдельно.

bsl
ВЫБРАТЬ
	Товары.Ссылка КАК Номенклатура,
	ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток,
	ЕСТЬNULL(Продажи.КоличествоОборот, 0) КАК Продано,
	ЕСТЬNULL(Остатки.КоличествоОстаток, 0) + ЕСТЬNULL(Продажи.КоличествоОборот, 0) КАК Итого
ИЗ
	Справочник.Номенклатура КАК Товары
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
		ПО Товары.Ссылка = Остатки.Номенклатура
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты КАК Продажи
		ПО Товары.Ссылка = Продажи.Номенклатура

NULL в условиях и соединениях: как не потерять строки

Проверка на NULL выполняется только оператором ЕСТЬ NULL или НЕ ... ЕСТЬ NULL. Конструкции ГДЕ Поле = NULL и ГДЕ Поле <> NULL не работают так, как ожидается: они не вернут ни одной строки, потому что любое сравнение с NULL даёт неопределённый результат.

Практический приём — отбирать товары без остатка: ГДЕ Остатки.Номенклатура ЕСТЬ NULL после левого соединения. Это типовой способ найти номенклатуру без движений, без цен или без штрихкодов.

Если условие накладывается на числовое поле из соединения, безопаснее сразу обернуть его в ЕСТЬNULL: ГДЕ ЕСТЬNULL(Остатки.КоличествоОстаток, 0) > 0. Иначе строки с NULL молча выпадут, и итоговая выборка будет меньше ожидаемой.

NULL в итогах, группировках и агрегатных функциях

Агрегатные функции ведут себя с NULL по-разному. СУММА, МИНИМУМ, МАКСИМУМ и СРЕДНЕЕ игнорируют NULL-значения. КОЛИЧЕСТВО(Поле) не считает NULL, а КОЛИЧЕСТВО(*) считает все строки. Это создаёт ловушку: среднее по полю с NULL выше, чем среднее, где NULL заменён нулём, потому что нули участвуют в расчёте.

Поэтому заменять NULL на 0 в поле, по которому считается СРЕДНЕЕ, нужно осознанно. Если бизнес-смысл — «нет продаж = 0 продаж», замена корректна. Если NULL означает «данные неизвестны», замена исказит статистику.

При группировках с итогами NULL появляется в группировочных полях строк итогов. В обходе результата запроса это видно по типу группировки: у итоговых записей детальные поля равны NULL. При программной обработке проверяйте ТипЗаписи() выборки, прежде чем обращаться к полям.

Типичные ошибки
01
Сравнение «Поле = 0» вместо обработки NULL — строки с NULL теряются из выборки
02
ЕСТЬNULL только вокруг одного слагаемого — второе поле с NULL всё равно обнуляет сумму
03
Замена NULL на 0 в поле для СРЕДНЕЕ — среднее занижается без необходимости
04
Проверка «= NULL» вместо «ЕСТЬ NULL» — условие никогда не срабатывает
05
ЕСТЬNULL с несовместимым типом замены — ошибка исполнения запроса

NULL в СКД и вычисляемых полях

В системе компоновки данных ЕСТЬNULL применяется прямо в тексте запроса набора данных — это предпочтительный способ. Если NULL появляется уже на уровне компоновки (например, при соединении нескольких наборов данных), используйте вычисляемое поле с выражением ЕСТЬNULL(Поле, 0) — функция доступна и в языке выражений СКД.

При связи наборов данных в СКД (например, остатки + продажи) несовпавшие связи дают NULL в ресурсах. Ресурсы с NULL в отчёте отображаются пустыми ячейками. Чтобы показать нули, добавьте вычисляемое поле или задайте выражение ресурса через ЕСТЬNULL.

Отдельный случай — параметры и отборы СКД. Сравнение в отборе «Равно 0» не найдёт строки с NULL. Если требуется отобрать и нулевые, и пустые, используйте условие в запросе с ЕСТЬNULL до передачи данных в компоновку.

Производительность и альтернативные подходы

ЕСТЬNULL в списке полей почти не влияет на скорость запроса. Заметные тормоза возникают, когда ЕСТЬNULL применяется в условии соединения или отбора по индексированному полю: СУБД не может использовать индекс, и происходит полное сканирование. По возможности накладывайте условия на исходное поле, а NULL обрабатывайте отдельной веткой логики.

Альтернатива ЕСТЬNULL — оператор ВЫБОР, когда логика сложнее простой замены: ВЫБОР КОГДА Остатки.Номенклатура ЕСТЬ NULL ТОГДА 0 КОГДА Остатки.КоличествоОстаток < 0 ТОГДА 0 ИНАЧЕ Остатки.КоличествоОстаток КОНЕЦ. Такой подход читается лучше при нескольких условиях.

Ещё одна стратегия — убрать NULL на уровне архитектуры запроса: вместо соединения справочника с виртуальной таблицей остатков сначала собрать во временную таблицу все нужные комбинации, а потом соединять. Это не отменяет ЕСТЬNULL, но делает запрос предсказуемее и проще для отладки.

Сравнение вариантов

ЕСТЬNULL(Поле, 0)

Стандартный краткий способ; подходит для простой замены. Ограничение — одинаковый тип аргументов

ВЫБОР КОГДА ... ЕСТЬ NULL

Гибкая логика с несколькими условиями; громоздко для простой замены нуля

Обработка в коде после запроса

Проверка ЗначениеЗаполнено() или = NULL при обходе выборки; уместно, когда логика не умещается в запрос

Проверка результата после доработки запроса

После добавления ЕСТЬNULL убедитесь, что запрос возвращает ожидаемое число строк: до доработки строки с NULL могли отсекаться условиями, после — появляться с нулями. Сравните количество строк и итоговые суммы по контрольному периоду.

Проверьте типы полей результата: если замена в ЕСТЬNULL задана числом 0, а исходное поле имеет точность 15,3, убедитесь, что отчёт или код, потребляющий результат, корректно работает с этим типом.

Для отчётов на СКД дополнительно прогоните вариант отчёта с разными отборами и периодами: NULL часто всплывает только на данных, где часть измерений пуста, например при отборе по складу без движений.

Контрольные точки

Как проверить результат

Количество строк результата
Норма

Все ожидаемые позиции присутствуют, пустые показатели выведены нулями

Тревожный признак

Строк итоговой выборки меньше, чем записей в основной таблице

Арифметика по строке
Норма

Сумма полей считается для каждой строки

Тревожный признак

Итоговая колонка пустая в части строк

Итоги отчёта
Норма

Суммы совпадают с контрольным расчётом

Тревожный признак

Итоги изменились без изменения данных

FAQ

Чем ЕСТЬNULL отличается от проверки «ЕСТЬ NULL»?

ЕСТЬNULL — функция, которая возвращает значение: либо само поле, либо замену. «ЕСТЬ NULL» — логический оператор для условий ГДЕ и ВЫБОР, он только проверяет факт отсутствия значения и возвращает ИСТИНА или ЛОЖЬ. Обычно они дополняют друг друга: проверка в условии, замена в полях.

Почему запрос с «ГДЕ Поле <> 0» не показывает часть строк?

Потому что сравнение с NULL не даёт ни ИСТИНА, ни ЛОЖЬ, и такие строки исключаются из результата. Используйте «ГДЕ ЕСТЬNULL(Поле, 0) <> 0» или добавьте условие «ИЛИ Поле ЕСТЬ NULL», если пустые строки тоже нужны.

Можно ли в ЕСТЬNULL подставить строку вместо числа?

Нет, типы аргументов должны быть совместимы. Для числового поля замена — число, для строкового — строка, для даты — дата (обычно ДАТАВРЕМЯ(1,1,1)). Если нужно показать текст «нет данных», делайте это в вычисляемом поле СКД или при выводе, а не в запросе.

Почему после ЕСТЬNULL среднее значение в отчёте стало ниже?

СРЕДНЕЕ игнорирует NULL, но учитывает нули. Заменив NULL на 0, вы добавили в расчёт новые значения, и среднее снизилось. Решите по смыслу: если «нет данных» не равно «ноль», оставьте NULL для поля среднего.

Работает ли ЕСТЬNULL в обращениях через точку, например Контрагент.ИНН?

Да. Если ссылка битая или тип значения не подходит, выражение через точку даёт NULL, и ЕСТЬNULL(Документ.Контрагент.ИНН, \"\") вернёт пустую строку. Учтите, что разыменование через точку само по себе формирует дополнительные соединения и может замедлять запрос на больших таблицах.

Нужно ли обрабатывать NULL в параметрах виртуальных таблиц?

Да, если параметр может быть не задан. Незаполненный параметр отбора виртуальной таблицы — это NULL, и сравнение с ним не сработает. Передавайте в параметр явное значение или используйте условия вида «Номенклатура = &Номенклатура ИЛИ &Номенклатура = НЕОПРЕДЕЛЕНО» с предварительной проверкой в коде.

Итог

Что важно запомнить

NULL — отсутствие значения, а не ноль: он ломает арифметику, сравнения и отборы. Заменяйте его функцией ЕСТЬNULL с совместимым типом, проверяйте через «ЕСТЬ NULL», помните о влиянии замены на СРЕДНЕЕ и всегда сверяйте итоги после доработки запроса.