Как добавить в запрос 1С динамическое условие, которое можно включать и отключать?

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

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

Самый очевидный, но не самый лучший способ — это динамическое построение текста запроса через сложение строк ("склеивание" или конкатенация). Автор исходной темы столкнулся именно с этой проблемой: такой подход, хоть и работает, сильно затрудняет дальнейшую разработку, отладку и поддержку кода. Текст запроса становится "рваным", его нельзя целиком открыть в конструкторе, и в нем легко допустить синтаксическую ошибку.

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

Метод 1: Логический флаг и оператор «ИЛИ»

Это, пожалуй, самый популярный, простой и эффективный способ. Суть заключается в том, чтобы добавить в запрос специальный булевский параметр (флаг), который будет "включать" или "выключать" основное условие фильтрации.

Логика условия в секции ГДЕ строится следующим образом:

(...условие отключено...) ИЛИ (...основное условие фильтрации...)

Если первая часть (...условие отключено...) принимает значение ИСТИНА, то вся конструкция становится истинной для любой строки, и основное условие не проверяется. Если же первая часть — ЛОЖЬ, то результат будет зависеть от второй части, то есть от основного условия.

Посмотрим на пример. Нам нужно добавить отбор по валюте.

Текст запроса будет выглядеть так:


ВЫБРАТЬ
    Документ.Ссылка
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК Документ
ГДЕ
    (&ИспользоватьОтборПоВалюте = ЛОЖЬ ИЛИ Документ.Валюта = &Валюта)

А в коде на 1С перед выполнением запроса мы устанавливаем параметры:


// ...
Запрос = Новый Запрос;
Запрос.Текст = "...текст запроса выше...";

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

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

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

Метод 2: Конструкция «ВЫБОР КОГДА»

Этот метод является аналогом оператора CASE в стандартном SQL и предлагает еще большую гибкость. Он позволяет в зависимости от значения параметра либо применять условие, либо возвращать ИСТИНА, что полностью отключает фильтрацию по данной строке.

В этом случае мы можем передавать в параметре само значение для отбора. Если значение не заполнено (например, НЕОПРЕДЕЛЕНО или пустая ссылка), условие не применяется.

Пример для отбора по валюте:


ГДЕ
    ВЫБОР
        КОГДА &Валюта = ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка)
            ТОГДА ИСТИНА
        ИНАЧЕ Документ.Валюта = &Валюта
    КОНЕЦ

В коде мы просто передаем либо конкретную валюту, либо пустую ссылку, если фильтр не нужен.

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

Пример с несколькими динамическими условиями:


...
ГДЕ
    (ВЫБОР
        КОГДА &ЕстьОрганизация
            ТОГДА Таблица.Организация = &Организация
        ИНАЧЕ ИСТИНА
    КОНЕЦ)
    И (ВЫБОР
        КОГДА &ЕстьСтатьиЗатрат
            ТОГДА НЕ Таблица.Субконто2 В ИЕРАРХИИ (&спСтатейЗатратИсключений)
        ИНАЧЕ ИСТИНА
    КОНЕЦ)

Здесь для каждого условия используется свой булевский флаг (&ЕстьОрганизация, &ЕстьСтатьиЗатрат), что делает код очень наглядным.

Важное замечание по производительности: сложные конструкции, такие как ВЫБОР, в секции ГДЕ могут влиять на скорость выполнения запроса. Рекомендуется размещать их после основных, более простых и селективных условий (особенно по индексированным полям). Это позволит СУБД сначала максимально сократить выборку по индексам, а уже потом применять сложную логику к меньшему объему данных.

Метод 3: Использование Построителя Запроса

Для более сложных сценариев, особенно в отчетах и динамических списках, платформа 1С предлагает специализированные объекты. ПостроительЗапроса — один из них. Хотя он считается несколько устаревшим по сравнению с СКД, он все еще широко используется и отлично справляется с задачей динамических условий.

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

Разберем на примере. Допустим, у нас есть базовый запрос, и мы хотим динамически добавить условие на сумму.


ТекстЗапроса = 
"ВЫБРАТЬ
|    т.Регистратор
|ИЗ
|    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто КАК т
|ГДЕ
|    12 <> т.ВидСубконтоДт2
|{ГДЕ
|    (т.Сумма > 100) КАК ТолькоБольшиеСуммы
|}";

Обратите внимание на блок {ГДЕ ...}. Внутри него мы описываем условие (т.Сумма > 100) и даем ему псевдоним ТолькоБольшиеСуммы. Теперь в коде мы можем управлять этим условием по его псевдониму.


Построитель = Новый ПостроительЗапроса;
Построитель.Текст = ТекстЗапроса;

Построитель.ЗаполнитьНастройки(); // Важный шаг для инициализации

// Если нам нужно включить отбор по большим суммам
Если НужноФильтроватьПоСумме Тогда
    // Добавляем отбор по псевдониму "ТолькоБольшиеСуммы"
    ЭлементОтбора = Построитель.Отбор.Добавить("ТолькоБольшиеСуммы");
    ЭлементОтбора.Использование = Истина;
    ЭлементОтбора.Значение = Истина; // Включаем условие
КонецЕсли;

// Получаем итоговый запрос
Запрос = Построитель.ПолучитьЗапрос();
Результат = Запрос.Выполнить();

Когда отбор включен, Построитель сам сгенерирует корректный SQL-запрос, добавив наше условие через И. Если отбор выключен, этого условия в итоговом тексте просто не будет. Это очень мощный и структурированный подход, который полностью избавляет от ручных манипуляций с текстом.

Метод 4: Замена "якоря" в тексте запроса

Этот метод — компромисс между "рваным" запросом и полностью целостным. Он все еще основан на замене строк, но делает это более предсказуемо. Идея в том, чтобы вставить в текст запроса специальный параметр-"якорь", который затем будет заменен либо на реальное условие, либо на ИСТИНА.

Шаг 1. В тексте запроса создаем "точку вставки".


Запрос.Текст = "
ВЫБРАТЬ
    ...
ИЗ
    Таблица
ГДЕ
    &УсловиеПоВалюте";

Шаг 2. В коде перед выполнением запроса производим замену.


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

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

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

Плюсы этого метода:

  1. Исходный текст запроса можно открыть в конструкторе, если для параметра &УсловиеПоВалюте указать тип Булево.
  2. Он достаточно прост для понимания.

Минусы:

  1. Он хрупкий. Если кто-то позже изменит запрос, добавив, например, ИЛИ после якоря (ГДЕ &УсловиеПоВалюте ИЛИ Сумма = 0), логика может нарушиться, когда якорь заменится на ИСТИНА.
  2. Это все еще манипуляция со строками, которая считается плохой практикой.

Заключение

Мы рассмотрели несколько способов создания динамических условий в запросах 1С. Выбор конкретного метода зависит от сложности задачи:

← На главную