При работе с запросами в системе 1С:Предприятие программисты часто сталкиваются со стандартной задачей: необходимо наложить фильтр по списку значений (массиву), но если этот список пуст, запрос должен игнорировать фильтр и возвращать все доступные записи. Прямое использование оператора В (&Массив) в таких случаях не работает так, как ожидается, потому что если &Массив пуст, условие всегда возвращает Ложь, и результат запроса будет пустым.
В этой статье мы подробно разберем, почему так происходит, и рассмотрим несколько эффективных способов решения данной проблемы — от простых логических условий до оптимизированного динамического построения текста запроса.
Рассмотрим стандартную ситуацию. У нас есть запрос к табличной части документа, где мы хотим отобрать строки по конкретным скидкам. Если пользователь выбрал список скидок на форме, мы передаем их в запрос. Если не выбрал — хотим видеть всё.
Если написать просто:
ГДЕ
СкидкаНаценка В (&МассивСкидок)
То при пустом массиве платформа 1С транслирует это условие в SQL-запрос как нечто вроде WHERE 1=0. В итоге мы получаем пустую выборку. Наша задача — заставить запрос «игнорировать» это условие, если параметров нет.
Проанализируем наиболее популярный и простой в реализации метод. Мы добавим в запрос дополнительный логический параметр &ЕстьФильтр, который будет принимать значение Истина, если массив не пуст, и Ложь в противном случае.
Разберем реализацию этого метода по шагам. Сначала подготовим текст запроса:
ВЫБРАТЬ
РеализацияТовары.Номенклатура,
РеализацияТовары.Сумма,
РеализацияТовары.СкидкаНаценка
ИЗ
Документ.ЗаказКлиента.Товары КАК РеализацияТовары
ГДЕ
РеализацияТовары.Ссылка = &Ссылка
И (НЕ &ЕстьФильтр ПО Скидкам ИЛИ РеализацияТовары.СкидкаНаценка В (&МассивСкидок))
Теперь посмотрим на программный код, который устанавливает эти параметры:
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
Запрос.УстановитьПараметр("МассивСкидок", СписокВыбранныхСкидок);
// Проверяем наличие элементов в массиве или списке значений
ЕстьФильтр = ?(СписокВыбранныхСкидок.Количество() > 0, Истина, Ложь);
Запрос.УстановитьПараметр("ЕстьФильтрПоСкидкам", ЕстьФильтр);
Результат = Запрос.Выполнить();
Важный момент: использование конструкции ИЛИ в блоке ГДЕ иногда может привести к замедлению выполнения запроса на огромных таблицах, так как оптимизатор SQL не всегда корректно использует индексы. Однако для работы с табличными частями документов или небольшими регистрами этот способ идеален благодаря своей простоте.
В некоторых случаях для наглядности логики можно использовать оператор ВЫБОР. Проанализируем пример, предложенный в обсуждении темы:
ГДЕ
ВЫБОР
КОГДА &ЕстьФильтр
ТОГДА РеализацияТовары.СкидкаНаценка В (&МассивСкидок)
ИНАЧЕ ИСТИНА
КОНЕЦ
Эта логика работает идентично предыдущему варианту: если флаг установлен, применяется фильтрация по массиву. Если нет — условие превращается в ИСТИНА, что позволяет выбрать все записи.
Если мы работаем с высоконагруженной системой или очень большими таблицами (миллионы строк), лучше всего использовать динамическое добавление условий. В этом случае, если массив пуст, текст фильтра вообще не попадет в итоговый запрос к базе данных.
Рассмотрим, как это реализовать программно:
ТекстЗапроса =
"ВЫБРАТЬ
| РеализацияТовары.Номенклатура,
| РеализацияТовары.Сумма
|ИЗ
| Документ.ЗаказКлиента.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Ссылка = &Ссылка";
Если СписокВыбранныхСкидок.Количество() > 0 Тогда
ТекстЗапроса = ТекстЗапроса + "
| И РеализацияТовары.СкидкаНаценка В (&МассивСкидок)";
Запрос.УстановитьПараметр("МассивСкидок", СписокВыбранныхСкидок);
КонецЕсли;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
Результат = Запрос.Выполнить();
Выясним причины, почему этот метод считается лучшим:
СкидкаНаценка.&ЕстьФильтр.Часто программисты сталкиваются с тем, что в коде запрос работает, а в консоли запросов — нет (или наоборот). Проанализируем ситуацию пользователя из сообщения №17.
Причина часто кроется в том, что в Консоли запросов параметр типа «Массив» или «Список значений» может быть инициализирован как пустой, но иметь определенный тип (например, СправочникСсылка.СкидкиНаценки), либо не иметь его вовсе. Если вы тестируете сложные условия с ВЫБОР или ИЛИ, убедитесь, что параметры в консоли заполнены точно так же, как они заполняются в коде (тип, состав, количество элементов).
Подведем итог и выясним, какой метод выбрать в вашей ситуации:
СписокЗначений всегда проверяйте его методом Количество() перед установкой параметров, чтобы правильно определить состояние фильтра.Рассмотренные подходы позволяют избежать распространенной ошибки «пустого результата» и сделать ваши запросы более гибкими и устойчивыми к изменениям входных данных.