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

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

В процессе разработки на платформе 1С программисты часто сталкиваются с необходимостью изменять текст запроса "на лету" в зависимости от установленных пользователем фильтров. Например, если флаг "Отбор по организации" установлен, мы должны добавить соответствующее условие в блок ГДЕ, а если нет — запрос должен выполняться по всем организациям. Рассмотрим подробно, как реализовать такую логику правильно, эффективно и с соблюдением стандартов разработки.

Способ 1. Конкатенация строк (Сборка текста запроса)

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

Проанализируем ситуацию: нам нужно добавить условие по организации только в том случае, если переменные ПоОрганизации и ВыборОрганизации истинны. Посмотрим, как это реализовать программно:


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

Если ПоОрганизации И ВыборОрганизации Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |   И ВзаиморасчетыОстатки.Организация = &Организация";
КонецЕсли;

Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Контрагент", ВыбранныйКонтрагент);
Запрос.УстановитьПараметр("Период", ДатаОтчета);

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

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

Способ 2. Универсальный фильтр (Логическое ИЛИ)

Существует элегантный способ оставить текст запроса статичным, но сделать условие необязательным. Для этого используется логическая конструкция ИЛИ. Рассмотрим, как это работает в коде 1С:


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

Запрос.УстановитьПараметр("Контрагент", ВыбранныйКонтрагент);
Запрос.УстановитьПараметр("Организация", ВыбраннаяОрганизация);
// Если флаг установлен в Истина, условие по Организации будет проигнорировано СУБД
Запрос.УстановитьПараметр("НеДелатьОтборПоОрганизации", НЕ (ПоОрганизации И ВыборОрганизации));

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

Способ 3. Оптимизация: Параметры виртуальных таблиц

Разберем критическую ошибку, которую часто допускают при работе с регистрами накопления. В исходном сообщении автора отбор по организации накладывался в блоке ГДЕ. С точки зрения производительности 1С — это неправильно. Проанализируем почему: блок ГДЕ фильтрует уже полученный результат из базы данных. Если мы работаем с виртуальной таблицей Остатки, правильнее передавать условия напрямую в её параметры.

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


ТекстУсловия = "Контрагент = &Контрагент";
Если ПоОрганизации И ВыборОрганизации Тогда
    ТекстУсловия = ТекстУсловия + " И Организация = &Организация";
КонецЕсли;

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

Этот метод заставляет СУБД выполнять фильтрацию на самом раннем этапе — при чтении данных из таблиц итогов, что значительно ускоряет выполнение запроса.

Способ 4. Схема запроса (QuerySchema)

Для наиболее сложных случаев, когда запрос меняется радикально, рекомендуется использовать объект СхемаЗапроса. Это мощный инструмент платформы 8.3, позволяющий программно манипулировать структурой запроса как объектом, а не текстом. Посмотрим на краткий пример логики:

  1. Создаем объект СхемаЗапроса и загружаем в него базовый текст.
  2. Получаем доступ к нужным пакетам и операторам (например, через СхемаЗапроса.ПакетыЗапросов[0].Операторы[0]).
  3. Добавляем элементы в массив Отбор.
  4. Выгружаем итоговый текст обратно в Запрос.Текст.

Использование схемы гарантирует отсутствие синтаксических ошибок (например, забытых запятых или закрывающих скобок), которые часто возникают при ручной склейке строк +.

Решение задачи с нулевыми остатками по контрагенту

В ходе обсуждения на форуме выяснилось, что автору нужно найти контрагентов, у которых общий баланс по всем договорам равен нулю, при этом в разрезе отдельных договоров долги могут быть. Рассмотрим решение этой задачи с помощью группировки и условия ИМЕЮЩИЕ.

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


ВЫБРАТЬ
    ВзаиморасчетыОстатки.Контрагент КАК Контрагент
ИЗ
    РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(&Период, ) КАК ВзаиморасчетыОстатки
СГРУППИРОВАТЬ ПО
    ВзаиморасчетыОстатки.Контрагент
ИМЕЮЩИЕ
    СУММА(ВзаиморасчетыОстатки.СуммаВзаиморасчетовОстаток) = 0

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

Итоги и рекомендации

Подведем итог нашему разбору. При выборе метода добавления параметров по условию руководствуйтесь следующими правилами:

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

← На главную