Язык запросов 1С

Проверка на пустое значение в запросе 1С: NULL, пустая ссылка, дата

Коротко

«Пусто» в запросе 1С — это три разных значения, и проверяются они по-разному. NULL (нет данных, обычно после ЛЕВОЕ СОЕДИНЕНИЕ) — только через оператор ЕСТЬ NULL / ЕСТЬ НЕ NULL, а не через =. Пустая ссылка — через = ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка). Пустая дата и строка — сравнением с параметром (&ПустаяДата) или с "".

Чтобы заменить NULL на осмысленное значение прямо в запросе, используйте функцию ЕСТЬNULL(Поле, Замена) или конструкцию ВЫБОР КОГДА … ТОГДА … КОНЕЦ. Во встроенном языке (не в запросе) универсальная проверка — глобальная функция ЗначениеЗаполнено().

NULL, пустая ссылка и незаполненное значение — в чём разница

Главная причина, почему проверка на пустое значение в запросе 1С «не срабатывает» — три разных состояния путают между собой:

  • NULL — данных физически нет. Появляется при ЛЕВОЕ СОЕДИНЕНИЕ, когда справа нет соответствия, а также при обращении к реквизитам, которых нет у объекта (реквизиты элемента у группы справочника и наоборот).
  • Пустая ссылка — значение ссылочного типа есть, но не заполнено (например, поле «Контрагент» осталось незаполненным). Это не NULL.
  • Пустая дата и пустая строка — примитивные типы со значением по умолчанию: '00010101000000' и "".

Ключевой момент: NULL нельзя сравнивать через =. Условие Поле = NULL всегда даёт неопределённый результат и не отбирает строки. Для NULL есть отдельный оператор, для пустой ссылки — своя конструкция. Разберём по порядку.

Проверка на NULL: оператор ЕСТЬ NULL и ЕСТЬ НЕ NULL

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

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

Оператор работает и в секции ГДЕ, и внутри ВЫБОР КОГДА. Не путайте его с функцией ЕСТЬNULL() (о ней ниже): ЕСТЬ NULL — это проверка, возвращающая Истина/Ложь, а ЕСТЬNULL() — замена значения.

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

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

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

Без ЕСТЬNULL() сумма NULL + 100 в запросе даст NULL, а не 100 — любое арифметическое действие с NULL «обнуляет» результат. Поэтому заменяйте NULL до арифметики только тогда, когда по смыслу отсутствующее значение действительно равно нулю.

ЕСТЬNULL: тип замены и положение относительно СУММА

Руководство 8.3.27, §8.4.17.4.11, и методика ИТС описывают приведение замены к строковому или числовому типу первого аргумента. Не используйте ЕСТЬNULL как универсальный способ расширить строку или разрядность числа. При необходимости явно задайте требуемый тип выражения и проверьте результат на целевой платформе и СУБД.

Руководство описывает приведение замены к строковому или числовому типу первого аргумента. Однако в проверенных сценариях файловой базы 8.3.27.1989, включая типизированное поле после левого соединения, замена не усеклась. Не рассчитывайте на ЕСТЬNULL как на средство принудительного ограничения длины; проверяйте нужный контекст отдельно.

// Замена после агрегата защищает итог пустой выборки.
ВЫБРАТЬ ЕСТЬNULL(СУММА(Данные.Количество), 0) КАК Количество
ИЗ ВТ_Данные КАК Данные

ЕСТЬNULL(СУММА(Поле), 0) и СУММА(ЕСТЬNULL(Поле, 0)) расположены на разных уровнях вычисления. Вторая форма заменяет значения существующих строк, но не создаёт строк в пустой исходной выборке. Решайте отдельно, означает ли NULL ноль или отсутствие наблюдения: для среднего такая замена изменит знаменатель.

Пустая ссылка в запросе: проверка через ЗНАЧЕНИЕ

Пустая ссылка в запросе 1С — это не NULL. У каждого ссылочного типа есть служебное значение «пустая ссылка», и сравнивать поле нужно именно с ним — через оператор ЗНАЧЕНИЕ:

ВЫБРАТЬ
    Заказы.Ссылка
ИЗ
    Документ.ЗаказПокупателя КАК Заказы
ГДЕ
    Заказы.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)   // не заполнен контрагент

Обратное условие «ссылка заполнена» — через <>:

ГДЕ
    Заказы.Контрагент <> ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

Альтернатива — передать пустую ссылку параметром из встроенного языка. Это удобно, когда тип определяется динамически:

Запрос.Текст =
    "ВЫБРАТЬ Заказы.Ссылка
    |ИЗ Документ.ЗаказПокупателя КАК Заказы
    |ГДЕ Заказы.Контрагент = &ПустаяСсылка";
Запрос.УстановитьПараметр("ПустаяСсылка", Справочники.Контрагенты.ПустаяСсылка());

Внимание: для полей составного типа, где значение «ничего не выбрано», проверяйте фактическое значение: НЕОПРЕДЕЛЕНО или пустую ссылку допустимого типа. Составной тип не исключает хранения пустой ссылки.

Пустая дата и пустая строка в запросе (ДАТАВРЕМЯ(1, 1, 1) и &ПустаяДата)

Пустая дата в 1С хранится как минимальная дата начала эры 01.01.0001 00:00:00 ('00010101000000'). Проверить поле на пустую дату в секции ГДЕ или ВЫБОР КОГДА можно двумя равнозначными способами — через встроенный литерал языка запросов ДАТАВРЕМЯ(1, 1, 1) (удобно в СКД и динамических списках, где не нужно передавать параметр из кода) либо через параметр &ПустаяДата:

// Способ 1. Прямо в тексте запроса через литерал ДАТАВРЕМЯ(1, 1, 1)
ВЫБРАТЬ
    Задачи.Ссылка КАК Задача
ИЗ
    Задача.ЗадачаИсполнителя КАК Задачи
ГДЕ
    Задачи.ДатаЗавершения = ДАТАВРЕМЯ(1, 1, 1)   // дата не заполнена

// Способ 2. Через параметр из встроенного языка
// Запрос.УстановитьПараметр("ПустаяДата", Дата(1, 1, 1));

Если поле даты получено из присоединённой таблицы после ЛЕВОЕ СОЕДИНЕНИЕ, там может оказаться как пустая дата ДАТАВРЕМЯ(1, 1, 1), так и NULL. Чтобы отобрать обе ситуации одним условием, оберните поле в ЕСТЬNULL:

ГДЕ
    ЕСТЬNULL(Оплаты.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1)

Пустая строка проверяется прямым сравнением с "". В языке запросов концевые пробелы при сравнении игнорируются, в отличие от BSL. СокрЛП имеет смысл для явного удаления начальных и конечных пробелов, но не является обязательным условием сравнения с пустой строкой:

ГДЕ
    СокрЛП(Контрагенты.Комментарий) = ""   // комментарий не заполнен

ВЫБОР КОГДА для замены NULL и пустых значений

Когда логика сложнее простой замены, помогает конструкция ВЫБОР КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ. Она пригодится, чтобы одним полем показать статус заполненности:

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

Обратите внимание: сначала проверяем ЕСТЬ NULL (нет строки вообще), и только потом = 0 (строка есть, но количество нулевое) — это два разных случая пустоты.

ЗначениеЗаполнено вне запроса: проверка результата

В самом языке запросов функции ЗначениеЗаполнено нет. Но во встроенном языке она — универсальный способ проверить пустое значение после получения данных из выборки. Функция считает пустыми пустую ссылку, пустую дату, пустую строку, а также NULL и Неопределено:

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Если НЕ ЗначениеЗаполнено(Выборка.Контрагент) Тогда
        Сообщить("У заказа " + Выборка.Ссылка + " не заполнен контрагент");
    КонецЕсли;
КонецЦикла;

Это удобно для проверки «на выходе», но не заменяет отбор в запросе: если строк без значения много, отфильтровать их условием ГДЕ … ЕСТЬ NULL или = ЗНАЧЕНИЕ(…ПустаяСсылка) быстрее, чем перебирать всю выборку в цикле.

Частые ошибки при проверке на пустое значение в запросе 1С

  • Сравнение с NULL через =. Условие Поле = NULL никогда не истинно и молча не отбирает строки. Для NULL — только оператор ЕСТЬ NULL / ЕСТЬ НЕ NULL.
  • Путают NULL и пустую ссылку. После левого соединения приходит NULL, а незаполненный реквизит в основной таблице — пустая ссылка. Это разные проверки: ЕСТЬ NULL против = ЗНАЧЕНИЕ(…ПустаяСсылка).
  • Забыли обернуть поле в ЕСТЬNULL(). Любая арифметика с NULL даёт NULL — суммы и итоги «схлопываются». Подставляйте ноль только если это соответствует смыслу отсутствующего значения; для агрегатов отдельно проверьте пустой набор.
  • Сравнение составного поля с пустой ссылкой. Для поля составного типа возможны НЕОПРЕДЕЛЕНО и пустая ссылка допустимого типа; различайте эти состояния.
  • Проверка строки без СокрЛП. Не переносите правила сравнения BSL в запрос: концевые пробелы при сравнении строк в запросе игнорируются. Для явной нормализации начала и конца строки используйте СокрЛП.

Частые вопросы о проверке на пустое значение в запросе 1С

Почему условие Поле = NULL не работает в запросе 1С?

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

Чем отличается ЕСТЬ NULL от функции ЕСТЬNULL?

ЕСТЬ NULL — это оператор-проверка: он возвращает Истина/Ложь и применяется в секции ГДЕ или в ВЫБОР. ЕСТЬNULL(Поле, Замена) — это функция-замена: она возвращает второй аргумент, если первый равен NULL, и используется в списке выбираемых полей.

Как проверить пустую ссылку в запросе 1С?

Сравнением с оператором ЗНАЧЕНИЕ: Поле = ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка). Для поля составного типа проверьте, хранится ли НЕОПРЕДЕЛЕНО или пустая ссылка допустимого типа.