NULL в запросах 1С: откуда берётся пустота и как её убрать через ЕСТЬNULL

· 9 мин

Содержание

«Есть NULL» в 1С означает, что поле в результате запроса не содержит вообще никакого значения: ни нуля, ни пустой строки, ни пустой ссылки. Исправляют это функцией ЕСТЬNULL(Поле, ЗначениеЗамены) прямо в тексте запроса, например ЕСТЬNULL(Остатки.КоличествоОстаток, 0).

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

Что такое NULL в 1С и чем он отличается от пустых значений

NULL — отдельный тип значения в 1С:Предприятии 8.3. Он означает «значения нет совсем». В базе у реквизита справочника или документа так не бывает: у реквизита всегда есть пустое значение своего типа. NULL рождается в момент выполнения запроса.

Сравните четыре «пустоты», которые часто путают:

ЗначениеЧто этоГде встречается
NULLЗначения нет, строки в связанной таблице не нашлосьРезультат запроса
НеопределеноПустое значение составного типаРеквизиты составного типа, переменные
Пустая ссылкаСправочник.Контрагенты.ПустаяСсылка()Незаполненный ссылочный реквизит
0, "", пустая датаПустое значение примитивного типаЧисла, строки, даты

В языке запросов есть две похожие записи, их тоже путают:

  • 🔹 Поле ЕСТЬ NULL — условие. Возвращает Истина или Ложь. Пишется с пробелом. Отрицание: НЕ Поле ЕСТЬ NULL.
  • 🔹 ЕСТЬNULL(Поле, Замена) — функция. Возвращает само поле, а если оно NULL — значение замены. Пишется слитно.

В модуле NULL проверяют так:

Если Выборка.Сумма = NULL Тогда
	// значения нет
КонецЕсли;

Если ТипЗнч(Выборка.Сумма) = Тип("Null") Тогда
	// то же самое, явная проверка типа
КонецЕсли;

Функция ЗначениеЗаполнено(NULL) возвращает Ложь. Она удобна, когда пустой ноль и NULL для вас означают одно и то же. Если их нужно различать — проверяйте тип.

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

NULL почти всегда — следствие структуры запроса, а не порчи данных. Вот где он появляется.

Левое соединение без пары

ЛЕВОЕ СОЕДИНЕНИЕ берёт все строки левой таблицы. Если справа подходящей строки нет, все поля правой таблицы будут NULL.

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

Товар без движений по регистру попадёт в результат, но Остаток у него будет NULL, а не 0. Виртуальная таблица остатков не хранит нулевые строки, поэтому такой случай встречается постоянно.

Так же ведут себя ПРАВОЕ СОЕДИНЕНИЕ (NULL слева) и ПОЛНОЕ СОЕДИНЕНИЕ (NULL с любой стороны).

Обращение через точку к пустой ссылке

Запись Документ.Контрагент.ИНН внутри запроса платформа превращает в неявное левое соединение. Если Контрагент не заполнен, ИНН придёт как NULL.

Поле составного типа

Регистратор, субконто, «Документ основание» — поля составного типа. Запрос Движения.Регистратор.Склад вернёт NULL для тех регистраторов, у которых реквизита Склад нет. Платформа не выдаёт ошибку, она просто подставляет NULL.

Агрегатные функции

  • СУММА по группе, где все значения NULL, вернёт NULL.
  • МАКСИМУМ и МИНИМУМ по пустому набору — тоже NULL.
  • КОЛИЧЕСТВО(Поле) строки с NULL не считает, а КОЛИЧЕСТВО(*) считает все строки.

Объединение запросов

В ОБЪЕДИНИТЬ ВСЕ во второй части иногда пишут NULL КАК Сумма как заглушку для колонки. Потом этот NULL всплывает в итогах.

Чем NULL опасен: поведение в выражениях и условиях

NULL «заражает» всё, с чем соприкасается. Это главное, что нужно помнить.

  • ⚠️ Арифметика: Цена * NULL = NULL. Сумма в строке пропадёт целиком.
  • ⚠️ Сравнение: NULL = 0, NULL <> 0, NULL > 5 не дают Истину. Строка с NULL не пройдёт ни одно из этих условий.
  • ⚠️ Условие отбора: ГДЕ Остатки.КоличествоОстаток <> 1 молча выкинет товары без остатка — для них поле NULL, а не 0.
  • ⚠️ Модуль: Выборка.Остаток + 1 при NULL даёт исключение Преобразование значения к типу Число не может быть выполнено.
  • ⚠️ Отчёт на СКД: ячейка пустая, итог по группе может отличаться от ожидаемого.

Вот как это выглядит на числах. Товар А: цена 100, остаток 5. Товар Б: цена 200, остатка нет.

ВыражениеТовар АТовар Б
Цена * Остатки.КоличествоОстаток500NULL
Цена * ЕСТЬNULL(Остатки.КоличествоОстаток, 0)5000
Условие Остаток = 0Ложьне проходит
Условие ЕСТЬNULL(Остаток, 0) = 0ЛожьИстина

Как найти, где именно появляется NULL

Пустая ячейка в отчёте ещё не говорит, откуда она. Ищите по шагам.

  1. Выделите запрос. Скопируйте текст запроса из модуля или из схемы компоновки данных.
  2. Выполните его отдельно в консоли запросов (внешняя обработка, которую используют почти все разработчики) или в отладчике.
  3. Найдите колонку с NULL. В консоли такие значения обычно видны как NULL или пустое поле с особой отметкой.
  4. Определите источник поля. Посмотрите, из какой таблицы оно берётся и как эта таблица присоединена.
  5. Проверьте вид соединения. Если таблица справа в ЛЕВОМ СОЕДИНЕНИИ — это ваш случай.
  6. Проверьте разыменование через точку. Цепочки вида Ссылка.Реквизит.Реквизит дают NULL при пустом первом звене.
  7. Добавьте контрольную колонку, чтобы отделить «нет строки» от «есть строка с пустым значением»:
ВЫБОР
	КОГДА Остатки.Номенклатура ЕСТЬ NULL
		ТОГДА "Нет строки в регистре"
	ИНАЧЕ "Строка есть"
КОНЕЦ КАК Диагностика

Проверяйте на NULL именно поле соединения (Остатки.Номенклатура), а не числовой ресурс. Так вы увидите, что строки справа нет вовсе.

В отладчике NULL показывается в окне «Вычислить выражение» и в табло со значением Null и типом Null. Поставьте точку останова на строке, где падает исключение, и посмотрите, какое поле выборки пришло пустым.

Диагностика: выберите симптом

Как исправить NULL в запросе: пять рабочих способов

Способ 1. Функция ЕСТЬNULL

Самый частый и простой путь. Второй параметр — то, что подставится вместо NULL.

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

Замена должна быть того же типа, что поле: для чисел 0, для строк "", для ссылок ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка).

Способ 2. Конструкция ВЫБОР

Нужна, когда вместо NULL нужно подставить разное в зависимости от условия, или когда важно отличить «нет строки» от «ноль».

ВЫБОР
	КОГДА Остатки.КоличествоОстаток ЕСТЬ NULL
		ТОГДА "Нет на складе"
	КОГДА Остатки.КоличествоОстаток < 0
		ТОГДА "Отрицательный остаток"
	ИНАЧЕ "В наличии"
КОНЕЦ КАК Статус

Способ 3. Внутреннее соединение вместо левого

Если строки без пары вам не нужны, NULL не нужен тоже. Замените ЛЕВОЕ СОЕДИНЕНИЕ на ВНУТРЕННЕЕ СОЕДИНЕНИЕ — в результате останутся только товары с остатком.

Способ 4. Отбор в параметрах виртуальной таблицы

Условие на правую таблицу в ГДЕ превращает левое соединение в фактически внутреннее и роняет строки. Перенесите отбор в параметры виртуальной таблицы или в условие ПО:

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(
		&Дата,
		Склад = &Склад) КАК Остатки
	ПО Номенклатура.Ссылка = Остатки.Номенклатура

Так товары без остатка на выбранном складе останутся в выборке с NULL, который затем закрывает ЕСТЬNULL.

Способ 5. Обработка в модуле

Если запрос менять нельзя (типовой, на поддержке), обработайте значение в коде:

Остаток = ?(Выборка.Остаток = NULL, 0, Выборка.Остаток);

Типовую конфигурацию на поддержке правьте через расширение, а не снятием с поддержки — иначе следующее обновление станет заметно сложнее.

СпособКогда подходитРиски
ЕСТЬNULLНужен ноль или пустое значение вместо NULLТеряется разница «нет строки» / «ноль»
ВЫБОР ... ЕСТЬ NULLНужно разное поведениеГромоздкий текст запроса
Внутреннее соединениеСтроки без пары не нужныПропадут товары без остатка
Отбор в параметрахОтбор по правой таблицеНужно аккуратно перенести условия
Проверка в модулеЗапрос менять нельзяЛогика размазана между запросом и кодом

Ошибки, которые допускают при обработке NULL

  • ❌ ЕСТЬNULL после агрегации вместо до. СУММА(ЕСТЬNULL(Поле, 0)) и ЕСТЬNULL(СУММА(Поле), 0) дают разный результат, когда в группе нет ни одной строки. Если нужен ноль в итоговой строке — нужен второй вариант.
  • ❌ Сравнение = NULL в запросе. В языке запросов так не работает . Пишите ЕСТЬ NULL.
  • ❌ Замена не того типа. ЕСТЬNULL(Склад, 0) для ссылочного поля даст колонку составного типа, и отбор по складу начнёт вести себя странно.
  • ❌ Путаница NULL и Неопределено. Пустой реквизит составного типа — это Неопределено, а не NULL. Проверка ЕСТЬ NULL его не поймает.
  • ❌ ЕСТЬNULL на всякий случай на каждом поле. Запрос становится нечитаемым, а реальные проблемы соединений маскируются нулями.

Как не допускать NULL в новых запросах

Несколько правил, которые экономят время на отладку:

  1. Каждый раз, когда пишете ЛЕВОЕ СОЕДИНЕНИЕ, сразу оборачивайте поля правой таблицы, которые идут в расчёт.
  2. Отборы по правой таблице ставьте в параметры виртуальной таблицы или в ПО, а не в ГДЕ.
  3. Для полей составного типа используйте ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг) перед обращением к реквизиту. Так понятнее, где ожидать NULL.
  4. В ОБЪЕДИНИТЬ подставляйте заглушки нужного типа: 0 КАК Сумма, а не NULL КАК Сумма, если колонка потом суммируется.
  5. В конструкторе запроса проверяйте вкладку «Связи»: галочка «Все» у таблицы и есть левое соединение.
Проверка запроса на NULL перед выкладкой
Выполнено: 0 / 5

Чем искать NULL автоматически

Ручной просмотр подходит для одного отчёта. Для поиска по базе и коду есть инструменты.

  • 🔍 Консоль запросов. Добавьте в запрос ГДЕ Поле ЕСТЬ NULL и сразу увидите все проблемные строки.
  • 🔍 Синтакс-помощник и поиск по конфигурации в Конфигураторе. Глобальный поиск по ЛЕВОЕ СОЕДИНЕНИЕ показывает места, где NULL вероятен.
  • 🔍 Отладчик с остановкой по ошибке. Включите в настройках отладки остановку по ошибке: выполнение встанет на строке, где NULL попал в арифметику.
  • 🔍 Проверка кода в EDT. Среда 1С:EDT и подключаемые к ней проверки находят часть небезопасных обращений.
  • 🔍 Проверочный запрос на «висящие» ссылки. Левое соединение документа со справочником и отбор Справочник.Ссылка ЕСТЬ NULL показывают битые ссылки (<Объект не найден>), из-за которых тоже приходят пустые значения.

Частые вопросы

Почему ЕСТЬNULL не убирает пустоту в поле составного типа?
Пустое поле составного типа хранит Неопределено, а не NULL. ЕСТЬNULL на него не реагирует. Используйте ВЫБОР КОГДА Поле = НЕОПРЕДЕЛЕНО.
Работает ли ЕСТЬNULL в схеме компоновки данных?
Да. Функцию можно писать в тексте запроса набора данных и в выражениях вычисляемых полей и ресурсов СКД.
Влияет ли ЕСТЬNULL на скорость запроса?
Обработка значения в колонке выборки почти не стоит ресурсов. Тормозить может условие ГДЕ ЕСТЬNULL(Поле, 0) = 0 по большой таблице: такое условие хуже использует индексы.
Можно ли получить NULL из реквизита справочника напрямую?
Нет. При чтении объекта в модуле реквизит всегда имеет значение своего типа. NULL приходит только из запроса.
Чем ЕСТЬ NULL отличается от ЕСТЬNULL?
ЕСТЬ NULL с пробелом — условие, возвращает Истина или Ложь. ЕСТЬNULL слитно — функция замены, возвращает значение.