Как реализовать условное объединение (ОБЪЕДИНЕНИТЬ ВСЕ) в запросе 1С в зависимости от параметра

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

При разработке сложных отчетов или обработок на платформе 1С часто возникает задача динамического изменения структуры запроса. Одной из таких задач является включение или исключение целых блоков данных, соединяемых через оператор ОБЪЕДИНИТЬ ВСЕ, в зависимости от переданного пользователем параметра. Рассмотрим подробнее, какими способами можно добиться этого результата, проанализируем их преимущества и недостатки.

Способ 1: Использование логического условия в секции ГДЕ

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

Разберем этот метод на примере кода:


ВЫБРАТЬ
    Продажи.Номенклатура,
    Продажи.Количество
ИЗ
    РегистрНакопления.Продажи КАК Продажи

ОБЪЕДИНИТЬ ВСЕ

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

В данном случае, если в параметр &ДелатьОбъединение передать значение Ложь, СУБД отсечет все записи из второй таблицы еще на этапе выполнения. Этот подход позволяет сохранить структуру запроса в одном объекте Запрос, что удобно для отладки в консоли запросов.

Способ 2: Программная модификация текста запроса

Если мы хотим добиться максимальной производительности и не нагружать СУБД лишними частями плана выполнения, лучше всего использовать программное формирование текста. Мы можем подготовить базовый текст и добавлять к нему блок с ОБЪЕДИНИТЬ ВСЕ только при выполнении условия в коде 1С.

Проанализируем ситуацию, когда текст запроса хранится в переменной:


ТекстЗапроса = 
"ВЫБРАТЬ
|   Товары.Ссылка КАК Товар
|ИЗ
|   Справочник.Номенклатура КАК Товары";

Если Параметры.ДобавитьУслуги Тогда
    ТекстЗапроса = ТекстЗапроса + 
    "
    |ОБЪЕДИНИТЬ ВСЕ
    |ВЫБРАТЬ
    |   Услуги.Ссылка
    |ИЗ
    |   Справочник.Номенклатура КАК Услуги
    |ГДЕ
    |   Услуги.ЭтоУслуга = ИСТИНА";
КонецЕсли;

Запрос = Новый Запрос(ТекстЗапроса);

Также можно использовать функцию СтрЗаменить, если в шаблоне запроса заранее подготовлена строка-маркер или если вы хотите динамически удалять уже написанный блок. Однако будьте осторожны: прямая замена текста ОБЪЕДИНИТЬ ВСЕ на пустую строку может привести к синтаксической ошибке, если после оператора идет текст второго запроса. Нужно удалять весь блок целиком.

Способ 3: Профессиональный подход через Схему запроса

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

Посмотрим на примерный алгоритм работы:

  1. Создаем объект СхемаЗапроса и загружаем в него текущий текст.
  2. Находим нужный запрос в пакете.
  3. Если условие не выполняется, удаляем из коллекции Операторы лишний элемент (каждый оператор в коллекции после первого — это и есть часть объединения).
  4. Выгружаем измененный текст обратно в объект Запрос.

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

Способ 4: Оптимизация через пакетные запросы и временные таблицы

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

Такой подход позволяет оптимизатору MS SQL Server или PostgreSQL более эффективно строить план запроса. Выглядит это примерно так:


// В коде 1С определяем, какой запрос выполнить
Если &НужноОбъединять Тогда
    ТекстЧасти2 = "ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_Данные2 ИЗ ...";
Иначе
    // Создаем пустую таблицу с той же схемой, чтобы итоговый запрос не упал
    ТекстЧасти2 = "ВЫБРАТЬ Первые 0 ... ПОМЕСТИТЬ ВТ_Данные2 ИЗ ...";
КонецЕсли;

В итоговом запросе пакета мы просто пишем ОБЪЕДИНИТЬ ВСЕ из этих двух временных таблиц. Поскольку одна из них может быть пустой (благодаря ВЫБРАТЬ ПЕРВЫЕ 0), итоговый результат будет корректным, а нагрузка на сервер минимальной.

Важные нюансы и рекомендации

При использовании любого из перечисленных методов следует учитывать несколько критически важных моментов:

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

← На главную