Как проверить заполнение реквизита типа перечисление в запросе 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При написании запросов к базе данных 1С часто возникает задача отфильтровать записи по признаку заполненности определенного поля. Если для строк или чисел проверка очевидна, то при работе со ссылочными типами данных, в частности с перечислениями, начинающие разработчики нередко сталкиваются с затруднениями: как проверить, выбрано ли значение, не перебирая при этом все возможные элементы перечисления?

Разберем подробно все правильные способы проверки заполнения перечислений, проанализируем ошибки и выясним, как платформа 1С обрабатывает такие условия на уровне СУБД.

Основной способ: использование функции ЗНАЧЕНИЕ

Самым правильным, лаконичным и быстродействующим способом проверки реквизита ссылочного типа на незаполненность является сравнение с пустой ссылкой через литерал ЗНАЧЕНИЕ прямо в тексте запроса.

Посмотрим на пример запроса, в котором отбираются документы с незаполненным перечислением:


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

Обратим внимание на синтаксис: после имени перечисления указывается ключевое слово ПустаяСсылка без круглых скобок. В языке запросов 1С допустима также сокращенная форма записи — достаточно поставить точку после имени перечисления:


ГДЕ
    ВнутренниеДокументы.IIT_ОтказОтЗаключенияДоговора = ЗНАЧЕНИЕ(Перечисление.IIT_ОтказОтЗаключенияДоговора.)

Если же перед нами стоит противоположная задача — отобрать только те строки, где значение перечисления заполнено, мы используем оператор сравнения <>:


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

Почему не стоит использовать обращение через точку и проверку на NULL?

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

  1. Неявное соединение: обращение к полю через точку (Реквизит.Ссылка) заставляет платформу сгенерировать дополнительное левое соединение (LEFT JOIN) с таблицей перечисления на уровне SQL.
  2. Избыточная нагрузка: вместо простого сравнения поля в текущей таблице СУБД выполняет соединение и последующую фильтрацию, что замедляет выполнение запроса на больших объемах данных.
  3. Некорректная логика: если реквизит просто не заполнен, в базе данных хранится бинарный ноль (пустая ссылка), а вовсе не значение NULL.

Механика работы на уровне СУБД

Проанализируем, как пустая ссылка хранится физически. В базе данных пустая ссылка любого ссылочного типа (включая перечисления) представляет собой последовательность из 16 нулевых байтов (0x00000000000000000000000000000000).

Когда мы пишем ЗНАЧЕНИЕ(Перечисление.Имя.ПустаяСсылка), платформа 1С подставляет в итоговый SQL-запрос прямое сравнение поля с бинарным нулем. Если по реквизиту построен индекс, СУБД мгновенно найдет нужные записи по индексу без лишних затрат ресурсов.

Особенности при левых соединениях таблиц

Важно помнить о ситуациях, когда проверяемый реквизит находится в таблице, присоединенной через ЛЕВОЕ СОЕДИНЕНИЕ. Если строка в правой таблице не найдена, значение реквизита будет равно NULL, а не пустой ссылке.

Так как в SQL любое прямое сравнение с NULL возвращает ложь, условие Реквизит = ЗНАЧЕНИЕ(...) проигнорирует ненайденные строки. Чтобы учесть оба случая (и когда значение не заполнено, и когда самой записи нет), используем функцию ЕСТЬNULL:


ГДЕ
    ЕСТЬNULL(Таблица.Реквизит, ЗНАЧЕНИЕ(Перечисление.Имя.ПустаяСсылка)) = ЗНАЧЕНИЕ(Перечисление.Имя.ПустаяСсылка)

Либо явно перечисляем условия через оператор ИЛИ:


ГДЕ
    Таблица.Реквизит ЕСТЬ NULL
    ИЛИ Таблица.Реквизит = ЗНАЧЕНИЕ(Перечисление.Имя.ПустаяСсылка)

Работа с реквизитами составного типа

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

В таких случаях разберем следующие правила:

  1. Проверка заполнения конкретного перечисления:
    
    ГДЕ
        Таблица.Реквизит ССЫЛКА Перечисление.Имя
        И Таблица.Реквизит <> ЗНАЧЕНИЕ(Перечисление.Имя.ПустаяСсылка)
    
  2. Ограничение типа: если требуется дальнейшая работа с реквизитом, приводим его к нужному типу с помощью функции ВЫРАЗИТЬ(Таблица.Реквизит КАК Перечисление.Имя).
← На главную