При работе с запросами в 1С часто возникает задача проверить, заполнено ли поле, имеющее составной тип данных. Сложность заключается в том, что «пустое» значение для такого реквизита может быть представлено по-разному: это может быть значение Неопределено (когда тип еще не выбран) или пустая ссылка конкретного типа (например, Документ.ЗаказКлиента.ПустаяСсылка).
Стандартные проверки вроде ЕСТЬ NULL не работают, а вручную перебирать все возможные пустые ссылки в громоздкой конструкции ВЫБОР КОГДА ... неудобно и плохо масштабируется — при добавлении нового типа в состав придется изменять все такие запросы. Рассмотрим несколько подходов к решению этой задачи, от самых простых до наиболее производительных.
Самый лаконичный способ, который приходит на ум — это разыменование поля через точку и проверка на NULL. Этот метод позволяет проверить наличие пустой типизированной ссылки.
Пример запроса:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Сделка.Ссылка ЕСТЬ NULL
Несмотря на свою простоту, у этого метода есть существенные недостатки:
Неопределено. Данное условие сработает только для пустых типизированных ссылок. Если в поле хранится значение Неопределено, такая проверка его не отловит.Этот способ можно использовать для быстрых проверок, но в нагруженных системах и сложных запросах он может стать узким местом.
Это «лобовой» подход, заключающийся в явном перечислении всех возможных пустых значений прямо в тексте запроса.
Пример запроса:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
ВЫБОР
КОГДА РеализацияТоваровУслуг.Сделка = ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка) ТОГДА ИСТИНА
КОГДА РеализацияТоваровУслуг.Сделка = ЗНАЧЕНИЕ(Документ.СчетНаОплатуПокупателю.ПустаяСсылка) ТОГДА ИСТИНА
КОГДА РеализацияТоваровУслуг.Сделка = НЕОПРЕДЕЛЕНО ТОГДА ИСТИНА
// ... и так для всех 29 типов ...
ИНАЧЕ ЛОЖЬ
КОНЕЦ
Недостатки очевидны:
.Ссылка IS NULL, но все равно уступает наиболее оптимальному варианту примерно в 1.2-1.5 раза.Этот способ признан самым быстрым и масштабируемым. Его суть — программно сформировать массив, содержащий все возможные пустые значения для данного реквизита, и передать его в запрос в качестве параметра.
Процесс состоит из двух шагов.
Для этого нам нужно получить все типы, входящие в состав нашего реквизита, и для каждого из них создать пустую ссылку. Это можно сделать, обратившись к метаданным.
Пример кода для формирования массива:
Функция ПолучитьМассивПустыхЗначенийСделки()
СписокПустыхСсылок = Новый Массив;
// Обязательно добавляем Неопределено
СписокПустыхСсылок.Добавить(Неопределено);
// Обращаемся к метаданным конкретного реквизита
Для Каждого ТипИзСоставного Из Метаданные.Документы.РеализацияТоваровУслуг.Реквизиты.Сделка.Тип.Типы() Цикл
// Для ссылочных типов получаем пустую ссылку
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипИзСоставного);
Если Метаданные.Справочники.Содержит(ОбъектМетаданных)
ИЛИ Метаданные.Документы.Содержит(ОбъектМетаданных)
ИЛИ Метаданные.Перечисления.Содержит(ОбъектМетаданных)
// ... можно добавить и другие ссылочные типы (ПВХ, Задачи и т.д.)
Тогда
// Новый(Тип) для ссылочных типов создаст пустую ссылку
СписокПустыхСсылок.Добавить(Новый(ТипИзСоставного));
КонецЕсли;
КонецЦикла;
Возврат СписокПустыхСсылок;
КонецФункции
Альтернативный способ — использовать объект СхемаЗапроса. Он позволяет получить описание типов колонки, не выполняя сам запрос. Однако тесты показали, что прямое обращение к метаданным в данном случае работает немного быстрее.
Теперь передадим полученный массив в качестве параметра в запрос и используем оператор В (...) для проверки.
// Получаем массив
МассивПустыхСделок = ПолучитьМассивПустыхЗначенийСделки();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Сделка В (&МассивПустыхСделок)";
Запрос.УстановитьПараметр("МассивПустыхСделок", МассивПустыхСделок);
Результат = Запрос.Выполнить();
Если нужно найти непустые значения, используем конструкцию НЕ В (...).
Оптимизация: Чтобы не формировать массив при каждом выполнении запроса, его можно кэшировать. Например, сохранить в параметрах сеанса или в экспортной переменной общего модуля при старте системы.
Тесты, проведенные участниками обсуждения, наглядно показывают разницу в скорости выполнения запросов:
В (...) — самый быстрый метод. Принят за эталон (1x).ВЫБОР КОГДА ... — медленнее в 1.2 – 1.5 раза..Ссылка ЕСТЬ NULL — медленнее в 3.2 – 3.5 раза.Итог: для проверки реквизитов составного типа на пустое значение в запросах 1С наиболее эффективным, быстрым и поддерживаемым решением является программное формирование массива пустых значений на основе метаданных и использование оператора В (...). Этот подход позволяет избежать проблем с производительностью и упрощает дальнейшее сопровождение кода.