Как выполнить пакетный запрос через Построитель отчета и получить несколько результатов

Программист IT и автоматизация бизнеса
← На главную

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

Анализ проблемы: почему стандартный метод не подходит

Основная сложность заключается в архитектуре объекта ПостроительОтчета. Он создавался как инструмент для быстрого построения выходных форм (отчетов), где на выходе ожидается одна таблица или дерево. Если мы передадим в него текст, содержащий пакет запросов (разделенных символом «;»), метод Выполнить() вернет результат только последнего запроса в пакете. Все промежуточные таблицы, созданные с помощью инструкции ПОМЕСТИТЬ, останутся внутри контекста выполнения и не будут доступны для прямой итерации через методы построителя.

Проанализируем ситуацию: нам необходимо не просто выполнить запрос, а получить доступ к промежуточной временной таблице ВТ_Грузчики, чтобы заполнить вторую таблицу на форме, сохранив при этом все пользовательские настройки (фильтры по подразделениям, периодам и т.д.), которые были заданы в интерфейсе построителя.

Решение 1: Преобразование Построителя в объект Запрос

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

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

  1. Настроим ПостроительОтчета, заполнив его текст и установив параметры.
  2. В нужный момент (например, при нажатии кнопки «Обновить») получим из него готовый объект Запрос.
  3. Выполним этот запрос методом ВыполнитьПакет().

Посмотрим на пример кода, реализующий эту логику:


// 1. Предположим, Построитель уже инициализирован и в нем заполнены настройки
// Получаем объект Запрос с учетом всех установленных пользователем отборов
ЗапросИзПостроителя = ПостроительОтчета.ПолучитьЗапрос();

// 2. Для работы с временными таблицами нам понадобится менеджер
МенеджерВТ = Новый МенеджерВременныхТаблиц;
ЗапросИзПостроителя.МенеджерВременныхТаблиц = МенеджерВТ;

// 3. Выполняем пакет запросов
// Метод возвращает массив результатов, соответствующих каждому запросу в пакете
МассивРезультатов = ЗапросИзПостроителя.ВыполнитьПакет();

// 4. Обрабатываем результаты
// Если в пакете 4 запроса (как в примере из вопроса), то:
// Индекс 0 - ВТ_ГрузыПрошедшиеКонтроль (результат будет пустым, т.к. это ПОМЕСТИТЬ)
// Индекс 1 - ВТ_СтатусыСборки (аналогично)
// Индекс 2 - ВТ_Грузчики (аналогично)
// Индекс 3 - Основной SELECT

// Чтобы получить данные именно из ВТ_Грузчики, нужно либо добавить в конец пакета 
// ВЫБРАТЬ * ИЗ ВТ_Грузчики, либо прочитать ее из менеджера.

Решение 2: Явное получение данных из временных таблиц

Как мы выяснили, если запрос заканчивается инструкцией ПОМЕСТИТЬ, в массиве результатов ВыполнитьПакет() на этом месте будет пустое значение. Чтобы "вытащить" данные промежуточной таблицы (например, списка сотрудников), мы можем поступить двумя способами.

Способ А: Дополнение пакета. Мы можем программно добавить в текст запроса построителя еще одну секцию в конце:

ТекстЗапроса = ПостроительОтчета.Текст + "; ВЫБРАТЬ * ИЗ ВТ_Грузчики";

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

Способ Б: Использование Менеджера временных таблиц. Это более гибкий подход. После того как ЗапросИзПостроителя.Выполнить() отработал (даже если мы вызвали обычный метод Выполнить()), все временные таблицы живут в объекте МенеджерВременныхТаблиц, пока он не будет уничтожен.

Разберем пример получения данных через менеджер:


ЗапросКВременнойТаблице = Новый Запрос;
ЗапросКВременнойТаблице.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросКВременнойТаблице.Текст = "ВЫБРАТЬ * ИЗ ВТ_Грузчики";

ТаблицаГрузчиков = ЗапросКВременнойТаблице.Выполнить().Выгрузить();
// Теперь ТаблицаГрузчиков содержит актуальные данные с учетом всех фильтров построителя

Особенности использования фигурных скобок {} в пакете

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

Проанализируем ситуацию на примере из сообщения: отбор по сотруднику стоит внутри запроса, формирующего ВТ_Грузчики. Это абсолютно правильно с точки зрения производительности. Когда мы вызываем ПолучитьЗапрос(), построитель анализирует свои настройки Отбор. Если пользователь установил фильтр по полю Сотрудник, платформа автоматически заменит {ГДЕ RGS_ГрузчикиСрезПоследних.Сотрудник} на реальное условие ГДЕ Сотрудник = &Параметр1.

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

Почему это лучше, чем два отдельных запроса?

Многие разработчики задаются вопросом: "Не проще ли заполнить таблицу грузчиков отдельным запросом?". Рассмотрим преимущества пакетного выполнения в контексте Построителя отчета:

  1. Целостность данных: Вы используете одни и те же срезы последних и остатки. В высоконагруженных системах данные могут измениться между двумя независимыми запросами.
  2. Производительность: Обращение к БД происходит один раз. Временные таблицы в памяти сервера работают быстрее, чем повторное сканирование индексов регистров в разных запросах.
  3. Единые настройки: Вам не нужно вручную синхронизировать параметры и отборы между ПостроителемОтчета и вторым вспомогательным запросом. Метод ПолучитьЗапрос() делает это автоматически.

Рекомендация по развитию: переход на СКД

Хотя ПостроительОтчета остается рабочим инструментом для обычных форм и специфических задач, современные стандарты разработки 1С (начиная с версии 8.2) диктуют использование Системы компоновки данных (СКД).

Выясним, чем СКД помогла бы в данной задаче:

Если ваша конфигурация позволяет, рассмотрите возможность перевода данного функционала на СКД. Однако, если вы ограничены текущей архитектурой обработки, связка ПостроительОтчета.ПолучитьЗапрос() + ВыполнитьПакет() является наиболее технически грамотным и производительным решением.

← На главную