Разработка и Конфигурация · 10 мин
NULL в запросах 1С: проверка, замена и типичные ошибки
Как работать с NULL в запросах 1С: проверка ЕСТЬ NULL, функция ЕСТЬNULL, левые соединения, типичные ошибки и примеры кода для разработчика.
NULL в языке запросов 1С — это специальное значение, обозначающее отсутствие данных. Чаще всего оно появляется при левом соединении таблиц, когда в присоединяемой таблице не нашлось подходящей записи: поля справа заполняются значением NULL. Также NULL возникает при обращении к реквизитам через точку от «битых» ссылок и в результате некоторых агрегатных вычислений.
Главная опасность NULL в том, что он не равен ничему, включая сам себя. Сравнение Где Поле = NULL никогда не вернёт истину, а условие Поле <> NULL тоже не сработает так, как ожидает разработчик. Из-за этого запросы с NULL ведут себя неочевидно: строки «пропадают» из результата, суммы не сходятся, отчёты показывают пустые значения.
Для корректной работы язык запросов 1С предоставляет специальные инструменты: оператор ЕСТЬ NULL для проверки, функцию ЕСТЬNULL() для замены значения по умолчанию и конструкцию ВЫБОР для сложной логики. Ниже разобраны все практические сценарии с примерами кода.
Откуда берётся NULL в результатах запроса
Самый частый источник NULL — левое соединение. Если для строки левой таблицы не нашлось пары в правой, все поля правой таблицы в этой строке получают значение NULL. Например, при соединении справочника «Номенклатура» с виртуальной таблицей остатков товары без движений по складу вернут NULL в поле «КоличествоОстаток».
Второй источник — обращение к реквизиту через точку, когда ссылка пустая или «битая» (объект удалён, а ссылка осталась). Выражение Документ.Контрагент.ИНН вернёт NULL, если контрагент не заполнен или удалён. Третий случай — агрегатные функции и итоги: при группировке с конструкцией ИТОГИ поля, не участвующие в группировке, могут содержать NULL в итоговых строках.
Как проверить поле на NULL: оператор ЕСТЬ NULL
Для отбора записей с отсутствующими данными используется оператор ЕСТЬ NULL в секции ГДЕ. Он возвращает истину только тогда, когда поле действительно содержит NULL. Обратный отбор — записи, где данные есть, — строится через отрицание НЕ Поле ЕСТЬ NULL.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
Остатки.КоличествоОстаток КАК Остаток
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
ГДЕ
Остатки.КоличествоОстаток ЕСТЬ NULL
Такой запрос вернёт все товары, по которым нет записей в регистре остатков. Это типовой приём для поиска «зависших» позиций без движений. Обратите внимание: условие Остатки.КоличествоОстаток = 0 дало бы другой результат — оно нашло бы только товары с явно нулевым остатком, а записи без движений пропустило бы.
Замена NULL значением по умолчанию: функция ЕСТЬNULL
Функция ЕСТЬNULL(Выражение, ЗначениеЕслиNull) возвращает первый аргумент, если он не NULL, иначе — второй аргумент. Это основной способ «очистить» результат запроса от NULL перед выводом в отчёт или дальнейшими вычислениями.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
Критически важное ограничение: типы обоих аргументов должны быть совместимы. Если первый аргумент — число, второй тоже должен быть числом; подставить строку «нет данных» вместо числового NULL напрямую не получится. Для ссылочных полей вторым аргументом обычно указывают пустую ссылку нужного типа через функцию ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка).
Если нужно вывести текстовую пометку вместо числового NULL, используйте конструкцию ВЫБОР: ВЫБОР КОГДА Остатки.КоличествоОстаток ЕСТЬ NULL ТОГДА "Нет движений" ИНАЧЕ ... КОНЕЦ. Но помните, что в этом случае поле станет строковым и потеряет возможность суммирования.
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК ОстатокNULL в соединениях и условиях: что ломается чаще всего
Классическая ошибка — фильтрация по полю правой таблицы в секции ГДЕ после левого соединения. Условие ГДЕ Остатки.Склад = &Склад отсекает все строки, где соединение не нашло пары, потому что у NULL сравнение со складом ложно. Фактически левое соединение превращается во внутреннее, и товары без движений исчезают из выборки.
Если нужно сохранить строки без пары, условие по правой таблице следует переносить в секцию ПО соединения либо дополнять проверкой на NULL: ГДЕ (Остатки.Склад = &Склад ИЛИ Остатки.Склад ЕСТЬ NULL). Первый вариант обычно предпочтительнее, так как фильтрация на этапе соединения работает эффективнее.
Вторая частая проблема — арифметика с NULL. Сложение, вычитание или умножение, где один из операндов NULL, всегда даёт NULL. Выражение Цена * Остаток вернёт NULL для товаров без остатков, и итоговая сумма по документу «схлопнется». Поэтому перед вычислениями поля из присоединяемых таблиц всегда оборачивайте в ЕСТЬNULL.
NULL при работе с итогами и группировками
При использовании секции ИТОГИ в итоговых записях поля, по которым не строится группировка, содержат NULL. Например, при итогах по контрагенту поле «Документ» в строке итога будет NULL. При обходе результата запроса в коде это нужно учитывать: проверяйте тип записи через ТипЗаписи() или обрабатывайте NULL перед использованием значения.
Агрегатные функции ведут себя с NULL по-разному. СУММА, СРЕДНЕЕ, МАКСИМУМ и МИНИМУМ игнорируют NULL-значения в группе, но если все значения группы NULL, результат тоже будет NULL. Функция КОЛИЧЕСТВО(Поле) не считает NULL-строки, а КОЛИЧЕСТВО(*) считает все строки группы — эта разница часто становится причиной расхождений в отчётах.
Как проверить результат
Все ожидаемые записи присутствуют, пустые значения заменены на 0 или пустую ссылку
Часть записей пропала — вероятно, фильтр по полю правой таблицы в ГДЕ
Итоговые суммы совпадают с контрольными данными
Итоги занижены или NULL — в вычисления попал NULL без ЕСТЬNULL
Нет значений NULL в выводе отчёта
Пустые ячейки там, где ожидались нули или значения по умолчанию
Практический порядок действий при отладке запроса с NULL
Если запрос возвращает неожиданный результат, действуйте последовательно. Сначала выведите подозрительное поле напрямую и проверьте, встречается ли NULL, — в консоли запросов NULL обычно отображается как пустое значение, поэтому надёжнее добавить вычисляемое поле ВЫБОР КОГДА Поле ЕСТЬ NULL ТОГДА 1 ИНАЧЕ 0 КОНЕЦ и посмотреть его значение.
Затем проверьте условия соединений и секцию ГДЕ на предмет фильтров по полям правых таблиц. После этого оберните все поля из присоединяемых таблиц, участвующие в вычислениях и выводе, в ЕСТЬNULL. В конце сравните количество строк и итоговые суммы до и после правок — они должны объясняться логикой изменений, а не «исчезновением» данных.
- 1Добавьте в выборку поле-флаг «ВЫБОР КОГДА Поле ЕСТЬ NULL ТОГДА 1 ИНАЧЕ 0 КОНЕЦ» и найдите строки с NULL
- 2Проверьте, не фильтруются ли поля правой таблицы в секции ГДЕ после левого соединения
- 3Перенесите условия по правой таблице в секцию ПО либо добавьте «ИЛИ Поле ЕСТЬ NULL»
- 4Оберните поля из присоединяемых таблиц в ЕСТЬNULL с совместимым типом значения по умолчанию
- 5Сверьте количество строк и итоговые суммы с контрольными данными
Частые вопросы о NULL в запросах 1С
Чем NULL отличается от пустой ссылки?
Пустая ссылка — это конкретное значение ссылочного типа, которое можно сравнить через «=» с ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка). NULL означает отсутствие значения вообще и не равен ничему, включая пустую ссылку. Реквизит с незаполненной ссылкой содержит пустую ссылку, а не NULL; NULL появляется при соединениях и обращениях через точку к несуществующим объектам.
Почему условие «Поле = NULL» не работает?
По правилам трёхзначной логики любое сравнение с NULL даёт неопределённый результат, который в отборе трактуется как ложь. Поэтому ни «= NULL», ни «<> NULL» не отбирают записи. Единственный корректный способ — оператор «ЕСТЬ NULL» и его отрицание «НЕ ... ЕСТЬ NULL».
Можно ли в ЕСТЬNULL подставить строку вместо числа?
Нет, типы аргументов должны быть совместимы, иначе запрос завершится ошибкой. Если нужна текстовая пометка, используйте конструкцию ВЫБОР с преобразованием числа в строку через ПРЕДСТАВЛЕНИЕ, но учтите, что поле перестанет быть числовым и потеряет возможность суммирования.
Почему после добавления условия в ГДЕ пропали строки?
Скорее всего, условие наложено на поле правой таблицы после левого соединения. Для строк без пары это поле равно NULL, сравнение даёт ложь, и строки отсекаются. Перенесите условие в секцию ПО соединения или дополните его проверкой «ИЛИ Поле ЕСТЬ NULL».
Как NULL влияет на агрегатные функции?
СУММА, СРЕДНЕЕ, МАКСИМУМ и МИНИМУМ игнорируют NULL внутри группы, но вернут NULL, если все значения группы пустые. КОЛИЧЕСТВО(Поле) не считает NULL-значения, а КОЛИЧЕСТВО(*) считает все строки. При расхождении показателей проверьте, какой именно вариант подсчёта используется.
Что делать с NULL в параметрах виртуальных таблиц?
Если параметр отбора может быть не заполнен, передавайте вместо него проверку в самом запросе: например, «ГДЕ (&Склад = НЕОПРЕДЕЛЕНО ИЛИ Склад = &Склад)». Устанавливать параметр в NULL и сравнивать его с полями бесполезно — такое сравнение никогда не даст истины.
Что важно запомнить
NULL нельзя сравнивать через «=» — только через «ЕСТЬ NULL». Для подстановки значения по умолчанию используйте ЕСТЬNULL с совместимым типом. Фильтры по полям правой таблицы после левого соединения размещайте в секции ПО, а перед вычислениями всегда очищайте поля от NULL.