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

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Разбор проблемы: почему оператор «В» не подходит для пустых списков

Рассмотрим стандартную ситуацию. У нас есть запрос к табличной части документа, где мы хотим отобрать строки по конкретным скидкам. Если пользователь выбрал список скидок на форме, мы передаем их в запрос. Если не выбрал — хотим видеть всё.

Если написать просто:


ГДЕ
    СкидкаНаценка В (&МассивСкидок)

То при пустом массиве платформа 1С транслирует это условие в SQL-запрос как нечто вроде WHERE 1=0. В итоге мы получаем пустую выборку. Наша задача — заставить запрос «игнорировать» это условие, если параметров нет.

Решение 1: Использование флага-параметра (классический метод)

Проанализируем наиболее популярный и простой в реализации метод. Мы добавим в запрос дополнительный логический параметр &ЕстьФильтр, который будет принимать значение Истина, если массив не пуст, и Ложь в противном случае.

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


ВЫБРАТЬ
    РеализацияТовары.Номенклатура,
    РеализацияТовары.Сумма,
    РеализацияТовары.СкидкаНаценка
ИЗ
    Документ.ЗаказКлиента.Товары КАК РеализацияТовары
ГДЕ
    РеализацияТовары.Ссылка = &Ссылка
    И (НЕ &ЕстьФильтр ПО Скидкам ИЛИ РеализацияТовары.СкидкаНаценка В (&МассивСкидок))

Теперь посмотрим на программный код, который устанавливает эти параметры:


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

// Проверяем наличие элементов в массиве или списке значений
ЕстьФильтр = ?(СписокВыбранныхСкидок.Количество() > 0, Истина, Ложь);
Запрос.УстановитьПараметр("ЕстьФильтрПоСкидкам", ЕстьФильтр);

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

Важный момент: использование конструкции ИЛИ в блоке ГДЕ иногда может привести к замедлению выполнения запроса на огромных таблицах, так как оптимизатор SQL не всегда корректно использует индексы. Однако для работы с табличными частями документов или небольшими регистрами этот способ идеален благодаря своей простоте.

Решение 2: Использование конструкции ВЫБОР КОГДА

В некоторых случаях для наглядности логики можно использовать оператор ВЫБОР. Проанализируем пример, предложенный в обсуждении темы:


ГДЕ
    ВЫБОР 
        КОГДА &ЕстьФильтр
            ТОГДА РеализацияТовары.СкидкаНаценка В (&МассивСкидок)
        ИНАЧЕ ИСТИНА
    КОНЕЦ

Эта логика работает идентично предыдущему варианту: если флаг установлен, применяется фильтрация по массиву. Если нет — условие превращается в ИСТИНА, что позволяет выбрать все записи.

Решение 3: Динамическое формирование текста запроса (оптимально для производительности)

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

Рассмотрим, как это реализовать программно:


ТекстЗапроса = 
"ВЫБРАТЬ
|   РеализацияТовары.Номенклатура,
|   РеализацияТовары.Сумма
|ИЗ
|   Документ.ЗаказКлиента.Товары КАК РеализацияТовары
|ГДЕ
|   РеализацияТовары.Ссылка = &Ссылка";

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

Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
Результат = Запрос.Выполнить();

Выясним причины, почему этот метод считается лучшим:

  1. Чистота SQL-кода: SQL-сервер получает максимально простой запрос без лишних логических ветвлений.
  2. Использование индексов: Оптимизатор СУБД гарантированно построит эффективный план выполнения, используя индексы по полю СкидкаНаценка.
  3. Отсутствие лишних параметров: Нам не нужно передавать дополнительные флаги &ЕстьФильтр.

Особенности тестирования в консоли запросов

Часто программисты сталкиваются с тем, что в коде запрос работает, а в консоли запросов — нет (или наоборот). Проанализируем ситуацию пользователя из сообщения №17.

Причина часто кроется в том, что в Консоли запросов параметр типа «Массив» или «Список значений» может быть инициализирован как пустой, но иметь определенный тип (например, СправочникСсылка.СкидкиНаценки), либо не иметь его вовсе. Если вы тестируете сложные условия с ВЫБОР или ИЛИ, убедитесь, что параметры в консоли заполнены точно так же, как они заполняются в коде (тип, состав, количество элементов).

Рекомендации по выбору метода

Подведем итог и выясним, какой метод выбрать в вашей ситуации:

Рассмотренные подходы позволяют избежать распространенной ошибки «пустого результата» и сделать ваши запросы более гибкими и устойчивыми к изменениям входных данных.

← На главную