Как правильно проверить заполнение параметра и реализовать необязательный отбор в запросе 1С?

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

При разработке отчетов и обработок на платформе 1С программисты часто сталкиваются с задачей реализации необязательного отбора. Например, если пользователь выбрал список групп номенклатуры, запрос должен отфильтровать данные по ним, а если список пуст — вывести всю информацию без ограничений.

Попытка проверить заполненность параметра непосредственно внутри текста запроса с помощью конструкции вида КОГДА &ГруппыТоваров <> НЕОПРЕДЕЛЕНО приводит к синтаксической ошибке:

«Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов.»

Проанализируем причину возникновения этой проблемы и разберем корректные способы реализации опциональных условий в языке запросов 1С.

Почему возникает ошибка при сравнении с НЕОПРЕДЕЛЕНО?

Язык запросов 1С строг к типам данных, участвующим в операциях сравнения (=, <>). Когда в параметр &ГруппыТоваров передается массив или список значений, платформа воспринимает его как коллекцию. Язык запросов не умеет напрямую сравнивать коллекцию со скалярным значением НЕОПРЕДЕЛЕНО на уровне СУБД. Это приводит к ошибке еще на этапе проверки типов перед отправкой SQL-запроса.

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

Способ 1. Использование дополнительного булева параметра (флага отбора)

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

Разберем реализацию этого способа на стороне программного кода 1С:


ЕстьОтбор = ГруппыНоменклатуры.Количество() > 0;

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТоварыОстатки.Номенклатура КАК Номенклатура,
    |	ТоварыОстатки.КоличествоОстаток КАК КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыОстатки
    |ГДЕ
    |	ВЫБОР
    |		КОГДА &ИспользоватьОтбор
    |			ТОГДА ТоварыОстатки.Номенклатура В ИЕРАРХИИ (&ГруппыТоваров)
    |		ИНАЧЕ ИСТИНА
    |	КОНЕЦ";

Запрос.УстановитьПараметр("ИспользоватьОтбор", ЕстьОтбор);
Запрос.УстановитьПараметр("ГруппыТоваров", ГруппыНоменклатуры.ВыгрузитьЗначения());

Обратите внимание на конструкцию в секции ГДЕ. Если флаг &ИспользоватьОтбор равен Ложь, выражение ВЫБОР возвращает ИСТИНА, и отбор по номенклатуре полностью игнорируется.

Важный нюанс при проверке Булево: Если существует вероятность, что в параметр &ИспользоватьОтбор может попасть значение не булева типа (например, НЕОПРЕДЕЛЕНО или NULL в результате работы сложных алгоритмов), безопаснее явно прописывать сравнение КОГДА &ИспользоватьОтбор = ИСТИНА. Это убережет запрос от аварийного завершения при неявных типах данных.

Способ 2. Динамическое формирование текста запроса

Хотя первый способ прост в реализации, логика с условием ВЫБОР ... ИНАЧЕ ИСТИНА в секции ГДЕ может негативно влиять на производительность при работе с большими объемами данных. Оптимизатор СУБД в некоторых случаях не может эффективно использовать индексы, что приводит к полному сканированию таблицы (Index Scan).

Более производительный подход — формировать условие ГДЕ в тексте запроса динамически, только когда отбор реально необходим.

Разберем пример с использованием метки подстановки и функции СтрЗаменить():


Запрос = Новый Запрос;
ТекстЗапроса = 
    "ВЫБРАТЬ
    |	ТоварыОстатки.Номенклатура КАК Номенклатура,
    |	ТоварыОстатки.КоличествоОстаток КАК КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыОстатки
    |&УсловиеОтбора";

Если ГруппыНоменклатуры.Количество() > 0 Тогда
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", "ГДЕ ТоварыОстатки.Номенклатура В ИЕРАРХИИ (&ГруппыТоваров)");
    Запрос.УстановитьПараметр("ГруппыТоваров", ГруппыНоменклатуры.ВыгрузитьЗначения());
Иначе
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", "");
КонецЕсли;

Запрос.Текст = ТекстЗапроса;

При таком подходе в SQL-сервер отправляется максимально чистый и оптимизированный код without лишних ветвлений.

Рекомендации и альтернативные механизмы

  1. Система компоновки данных (СКД): Если задача решается в рамках отчета или динамического списка, лучше всего использовать СКД. В СКД необязательные отборы поддерживаются «из коробки» с помощью фигурных скобок: {ГДЕ ТоварыОстатки.Номенклатура В ИЕРАРХИИ (&ГруппыТоваров)}. Если параметр не задан, платформа автоматически удалит условие из итогового SQL-запроса.
  2. Избегайте передачи пустой ссылки для иерархии: Передача значения Справочники.Номенклатура.ПустаяСсылка() в оператор В ИЕРАРХИИ формально выполнится без ошибки, но не вернет все данные, а лишь отфильтрует элементы без родителя, что нарушит логику работы программы.
← На главную