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

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

При работе с запросами в 1С часто возникает задача проверить, заполнено ли поле, имеющее составной тип данных. Сложность заключается в том, что «пустое» значение для такого реквизита может быть представлено по-разному: это может быть значение Неопределено (когда тип еще не выбран) или пустая ссылка конкретного типа (например, Документ.ЗаказКлиента.ПустаяСсылка).

Стандартные проверки вроде ЕСТЬ NULL не работают, а вручную перебирать все возможные пустые ссылки в громоздкой конструкции ВЫБОР КОГДА ... неудобно и плохо масштабируется — при добавлении нового типа в состав придется изменять все такие запросы. Рассмотрим несколько подходов к решению этой задачи, от самых простых до наиболее производительных.

Метод 1: Проверка через «.Ссылка IS NULL» (простой, но медленный)

Самый лаконичный способ, который приходит на ум — это разыменование поля через точку и проверка на NULL. Этот метод позволяет проверить наличие пустой типизированной ссылки.

Пример запроса:


ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка
ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
    РеализацияТоваровУслуг.Сделка.Ссылка ЕСТЬ NULL

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

  1. Низкая производительность. Как показали тесты, проведенные в ходе обсуждения, этот способ может быть в 3-3.5 раза медленнее оптимального. Причина в том, что для проверки СУБД может потребоваться выполнить соединения (JOIN) с каждой таблицей, тип которой входит в состав реквизита.
  2. Не обрабатывает Неопределено. Данное условие сработает только для пустых типизированных ссылок. Если в поле хранится значение Неопределено, такая проверка его не отловит.

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

Метод 2: Конструкция «ВЫБОР КОГДА…» (громоздкий и негибкий)

Это «лобовой» подход, заключающийся в явном перечислении всех возможных пустых значений прямо в тексте запроса.

Пример запроса:


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

Недостатки очевидны:

Метод 3: Использование массива пустых значений и оператора «В (...)» (оптимальный)

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

Процесс состоит из двух шагов.

Шаг 1. Формируем массив пустых значений

Для этого нам нужно получить все типы, входящие в состав нашего реквизита, и для каждого из них создать пустую ссылку. Это можно сделать, обратившись к метаданным.

Пример кода для формирования массива:


Функция ПолучитьМассивПустыхЗначенийСделки()

    СписокПустыхСсылок = Новый Массив;
    // Обязательно добавляем Неопределено
    СписокПустыхСсылок.Добавить(Неопределено);

    // Обращаемся к метаданным конкретного реквизита
    Для Каждого ТипИзСоставного Из Метаданные.Документы.РеализацияТоваровУслуг.Реквизиты.Сделка.Тип.Типы() Цикл
        
        // Для ссылочных типов получаем пустую ссылку
        ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипИзСоставного);
        Если Метаданные.Справочники.Содержит(ОбъектМетаданных)
            ИЛИ Метаданные.Документы.Содержит(ОбъектМетаданных)
            ИЛИ Метаданные.Перечисления.Содержит(ОбъектМетаданных)
            // ... можно добавить и другие ссылочные типы (ПВХ, Задачи и т.д.)
        Тогда
            // Новый(Тип) для ссылочных типов создаст пустую ссылку
            СписокПустыхСсылок.Добавить(Новый(ТипИзСоставного));
        КонецЕсли;

    КонецЦикла;

    Возврат СписокПустыхСсылок;

КонецФункции

Альтернативный способ — использовать объект СхемаЗапроса. Он позволяет получить описание типов колонки, не выполняя сам запрос. Однако тесты показали, что прямое обращение к метаданным в данном случае работает немного быстрее.

Шаг 2. Используем массив в запросе

Теперь передадим полученный массив в качестве параметра в запрос и используем оператор В (...) для проверки.


// Получаем массив
МассивПустыхСделок = ПолучитьМассивПустыхЗначенийСделки();

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

Запрос.УстановитьПараметр("МассивПустыхСделок", МассивПустыхСделок);

Результат = Запрос.Выполнить();

Если нужно найти непустые значения, используем конструкцию НЕ В (...).

Оптимизация: Чтобы не формировать массив при каждом выполнении запроса, его можно кэшировать. Например, сохранить в параметрах сеанса или в экспортной переменной общего модуля при старте системы.

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

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

  1. Проверка через массив В (...) — самый быстрый метод. Принят за эталон (1x).
  2. Конструкция ВЫБОР КОГДА ... — медленнее в 1.2 – 1.5 раза.
  3. Проверка через .Ссылка ЕСТЬ NULL — медленнее в 3.2 – 3.5 раза.

Итог: для проверки реквизитов составного типа на пустое значение в запросах 1С наиболее эффективным, быстрым и поддерживаемым решением является программное формирование массива пустых значений на основе метаданных и использование оператора В (...). Этот подход позволяет избежать проблем с производительностью и упрощает дальнейшее сопровождение кода.

← На главную