При разработке сложных инструментов визуализации данных на платформе 1С часто возникает ситуация, когда одного финального результата запроса недостаточно. Представим рабочее место диспетчера: на одной форме нам нужно вывести список заказов, а на другой — список доступных сотрудников с их текущей загрузкой. Использование Построителя отчета удобно тем, что оно предоставляет пользователю гибкие возможности настройки отборов и порядков. Однако стандартный метод Выполнить() возвращает только один результат. Разберем, как обойти это ограничение и эффективно работать с пакетными запросами в связке с построителем.
Основная сложность заключается в архитектуре объекта ПостроительОтчета. Он создавался как инструмент для быстрого построения выходных форм (отчетов), где на выходе ожидается одна таблица или дерево. Если мы передадим в него текст, содержащий пакет запросов (разделенных символом «;»), метод Выполнить() вернет результат только последнего запроса в пакете. Все промежуточные таблицы, созданные с помощью инструкции ПОМЕСТИТЬ, останутся внутри контекста выполнения и не будут доступны для прямой итерации через методы построителя.
Проанализируем ситуацию: нам необходимо не просто выполнить запрос, а получить доступ к промежуточной временной таблице ВТ_Грузчики, чтобы заполнить вторую таблицу на форме, сохранив при этом все пользовательские настройки (фильтры по подразделениям, периодам и т.д.), которые были заданы в интерфейсе построителя.
Самый эффективный способ решить задачу — использовать ПостроительОтчета как генератор текста запроса и хранилище параметров, а само выполнение доверить стандартному объекту Запрос. Платформа предоставляет для этого удобные механизмы.
Рассмотрим по шагам, как реализовать этот подход:
ПостроительОтчета, заполнив его текст и установив параметры.Запрос.ВыполнитьПакет().Посмотрим на пример кода, реализующий эту логику:
// 1. Предположим, Построитель уже инициализирован и в нем заполнены настройки
// Получаем объект Запрос с учетом всех установленных пользователем отборов
ЗапросИзПостроителя = ПостроительОтчета.ПолучитьЗапрос();
// 2. Для работы с временными таблицами нам понадобится менеджер
МенеджерВТ = Новый МенеджерВременныхТаблиц;
ЗапросИзПостроителя.МенеджерВременныхТаблиц = МенеджерВТ;
// 3. Выполняем пакет запросов
// Метод возвращает массив результатов, соответствующих каждому запросу в пакете
МассивРезультатов = ЗапросИзПостроителя.ВыполнитьПакет();
// 4. Обрабатываем результаты
// Если в пакете 4 запроса (как в примере из вопроса), то:
// Индекс 0 - ВТ_ГрузыПрошедшиеКонтроль (результат будет пустым, т.к. это ПОМЕСТИТЬ)
// Индекс 1 - ВТ_СтатусыСборки (аналогично)
// Индекс 2 - ВТ_Грузчики (аналогично)
// Индекс 3 - Основной SELECT
// Чтобы получить данные именно из ВТ_Грузчики, нужно либо добавить в конец пакета
// ВЫБРАТЬ * ИЗ ВТ_Грузчики, либо прочитать ее из менеджера.
Как мы выяснили, если запрос заканчивается инструкцией ПОМЕСТИТЬ, в массиве результатов ВыполнитьПакет() на этом месте будет пустое значение. Чтобы "вытащить" данные промежуточной таблицы (например, списка сотрудников), мы можем поступить двумя способами.
Способ А: Дополнение пакета. Мы можем программно добавить в текст запроса построителя еще одну секцию в конце:
ТекстЗапроса = ПостроительОтчета.Текст + "; ВЫБРАТЬ * ИЗ ВТ_Грузчики";
В этом случае последний элемент массива результатов будет содержать таблицу с нашими сотрудниками.
Способ Б: Использование Менеджера временных таблиц. Это более гибкий подход. После того как ЗапросИзПостроителя.Выполнить() отработал (даже если мы вызвали обычный метод Выполнить()), все временные таблицы живут в объекте МенеджерВременныхТаблиц, пока он не будет уничтожен.
Разберем пример получения данных через менеджер:
ЗапросКВременнойТаблице = Новый Запрос;
ЗапросКВременнойТаблице.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросКВременнойТаблице.Текст = "ВЫБРАТЬ * ИЗ ВТ_Грузчики";
ТаблицаГрузчиков = ЗапросКВременнойТаблице.Выполнить().Выгрузить();
// Теперь ТаблицаГрузчиков содержит актуальные данные с учетом всех фильтров построителя
Важно помнить, как ПостроительОтчета обрабатывает конструкции в фигурных скобках. Если вы используете пакетный запрос, убедитесь, что конструкции {ГДЕ ...} расставлены в тех частях пакета, где они логически необходимы.
Проанализируем ситуацию на примере из сообщения: отбор по сотруднику стоит внутри запроса, формирующего ВТ_Грузчики. Это абсолютно правильно с точки зрения производительности. Когда мы вызываем ПолучитьЗапрос(), построитель анализирует свои настройки Отбор. Если пользователь установил фильтр по полю Сотрудник, платформа автоматически заменит {ГДЕ RGS_ГрузчикиСрезПоследних.Сотрудник} на реальное условие ГДЕ Сотрудник = &Параметр1.
Если же отбор должен влиять на весь пакет, иногда бывает полезно продублировать условия в разных частях пакета, хотя чаще всего достаточно ограничить данные на этапе формирования первой же временной таблицы.
Многие разработчики задаются вопросом: "Не проще ли заполнить таблицу грузчиков отдельным запросом?". Рассмотрим преимущества пакетного выполнения в контексте Построителя отчета:
ПостроителемОтчета и вторым вспомогательным запросом. Метод ПолучитьЗапрос() делает это автоматически.Хотя ПостроительОтчета остается рабочим инструментом для обычных форм и специфических задач, современные стандарты разработки 1С (начиная с версии 8.2) диктуют использование Системы компоновки данных (СКД).
Выясним, чем СКД помогла бы в данной задаче:
СкомпоноватьРезультат() позволяет вывести обе таблицы в один документ или разделить их программно, используя ПроцессорКомпоновкиДанных.Если ваша конфигурация позволяет, рассмотрите возможность перевода данного функционала на СКД. Однако, если вы ограничены текущей архитектурой обработки, связка ПостроительОтчета.ПолучитьЗапрос() + ВыполнитьПакет() является наиболее технически грамотным и производительным решением.