При разработке сложных аналитических отчетов в системе 1С программисты часто сталкиваются с ситуацией, когда несколько разных отчетов или вариантов одного отчета базируются на одном и том же массивном блоке кода. Представьте ситуацию: у вас есть три макета компоновки данных, в каждом из которых запрос занимает более 2000 строк. При этом первые 900 строк (подготовка временных таблиц, расчет остатков, получение базовых цен) абсолютно идентичны. Как только в этой «общей» части обнаруживается ошибка или требуется внести изменение в логику, разработчик вынужден тиражировать правки во все макеты, что неизбежно ведет к рассинхронизации и возникновению новых багов.
В этой статье мы подробно разберем несколько стратегий, которые позволят вынести общую часть запроса в отдельное хранилище и динамически подключать к ней уникальные «хвосты» для каждого конкретного случая. Проанализируем как стандартные механизмы 1С, так и продвинутые архитектурные подходы.
Этот способ позволяет физически разделить выполнение запроса на два этапа: сначала подготавливается общая часть, результаты которой сохраняются в памяти (или в базе данных) в виде временных таблиц, а затем эти таблицы передаются в Систему компоновки данных (СКД) как готовый источник.
Разберем этот механизм по шагам. Сначала мы создаем общий модуль или процедуру, где выполняется основной «тяжелый» блок запроса. Результат мы помещаем в объект МенеджерВременныхТаблиц. Рассмотрим пример кода:
// 1. Подготовка общей части запроса
ЗапросОбщий = Новый Запрос;
ЗапросОбщий.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
ЗапросОбщий.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура,
| СУММА(Продажи.Количество) КАК КолВо
|ПОМЕСТИТЬ ВТ_ОбщиеДанные
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|СГРУППИРОВАТЬ ПО
| Продажи.Номенклатура";
ЗапросОбщий.Выполнить();
// 2. Инициализация СКД с передачей МВТ
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Важный момент: шестой параметр метода Инициализировать - это наш МенеджерВТ
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина, , ЗапросОбщий.МенеджерВременныхТаблиц);
В самой схеме компоновки данных (в конструкторе запроса) вам достаточно написать простой текст: ВЫБРАТЬ * ИЗ ВТ_ОбщиеДанные КАК Т. Система увидит таблицу, которая уже лежит в менеджере, и сможет с ней работать. Важно помнить: при таком подходе стандартные отборы СКД могут не «прокидываться» внутрь общего запроса автоматически, поэтому общую часть стоит проектировать с учетом максимально возможных фильтров.
Если разделение на два этапа выполнения (как в методе с МВТ) неприемлемо по соображениям производительности, мы можем использовать строковую сборку текста перед тем, как передать его в схему компоновки. Рассмотрим, как это реализовать наиболее элегантно.
Мы можем хранить общую часть в отдельном макете типа «Текст» или в общем модуле в виде строковой константы. Уникальные части («хвосты») хранятся в соответствующих макетах отчетов. Перед компоновкой мы объединяем их. Проанализируем пример функции сборки:
Функция ПолучитьПолныйТекстЗапроса(ИмяУникальногоМакета)
ОбщаяЧасть = ПолучитьОбщуюЧастьЗапроса(); // Функция возвращает 900+ строк кода
УникальныйХвост = ПолучитьМакет(ИмяУникальногоМакета).Текст;
// Соединяем части. Обычно уникальный хвост начинается с выбора из ВТ,
// созданных в общей части.
ПолныйТекст = ОбщаяЧасть + " ; " + Символы.ПС + УникальныйХвост;
Возвращает ПолныйТекст;
КонецФункции
Главный недостаток этого метода — потеря возможности использовать конструктор запроса в СКД для финального текста. Однако мы можем обойти это ограничение, используя отладчик. Выгрузив итоговый текст в консоль запросов, мы редактируем его там, а затем снова разделяем на «голову» и «хвост».
Для более продвинутой разработки, начиная с платформы 8.3.5, рекомендуется использовать объект СхемаЗапроса. Он позволяет манипулировать структурой запроса как объектом, а не как строкой. Это избавляет от ошибок, связанных с пропущенными запятыми или неверными именами временных таблиц при конкатенации.
Рассмотрим, как это работает. Мы инициализируем объект СхемаЗапроса и загружаем в него базовый текст. Затем программно добавляем новые пакеты запросов или условия:
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекст(ОбщийТекст); // Загружаем 900 строк базы
// Добавляем новый пакет (хвост)
ПакетХвост = Схема.ПакетныеЗапросы.Добавить(Тип("ПакетныйЗапросВыборкаСхемыЗапроса"));
ОператорВыбора = ПакетХвост.Операторы[0];
// Здесь мы программно описываем источники и поля
// ...
ИтоговыйТекст = Схема.ПолучитьТекст();
Проанализируем преимущества: СхемаЗапроса гарантирует синтаксическую корректность итогового кода. Мы можем программно находить нужные нам временные таблицы в общем блоке и изменять их «на лету» перед выполнением.
СКД поддерживает механизм вложенных отчетов. Это позволяет оформить общую часть как отдельный отчет или схему, а затем подключать ее в другие схемы. Выясним, почему это удобно:
Для реализации этого метода в основной схеме на закладке «Вложенные схемы» добавьте ссылку на общую схему. В настройках компоновщика укажите, какие поля из вложенной схемы должны быть доступны в основном отчете.
В типовых решениях от 1С (на базе БСП) часто применяется механизм тегов в комментариях запроса. Рассмотрим пример такого подхода:
ТекстЗапроса =
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ Регистр.Продажи;
|//#{УНИКАЛЬНЫЙ_БЛОК}
|ВЫБРАТЬ * ИЗ ВТ_Данные";
// Перед выполнением делаем замену
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "//#{УНИКАЛЬНЫЙ_БЛОК}", ТекстИзМакетаХвоста);
Это позволяет визуально видеть структуру всего запроса целиком, но при этом динамически вставлять в него специфичные куски кода в заранее определенные «точки расширения».
Подведем итог нашему анализу. Выбор метода зависит от ваших приоритетов:
СхемуЗапроса или строковую сборку.МенеджерВременныхТаблиц, чтобы не выполнять тяжелые расчеты трижды.В любом случае, уход от прямого дублирования 900 строк кода — это важный шаг к созданию надежной и расширяемой системы. Мы рекомендуем начать с программной сборки текста, так как это дает максимальный контроль над итоговым SQL-запросом при минимальных затратах на переработку архитектуры существующих отчетов.