Как организовать сопровождение длинных запросов с одинаковой общей частью?

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

При разработке сложных аналитических отчетов в системе 1С программисты часто сталкиваются с ситуацией, когда несколько разных отчетов или вариантов одного отчета базируются на одном и том же массивном блоке кода. Представьте ситуацию: у вас есть три макета компоновки данных, в каждом из которых запрос занимает более 2000 строк. При этом первые 900 строк (подготовка временных таблиц, расчет остатков, получение базовых цен) абсолютно идентичны. Как только в этой «общей» части обнаруживается ошибка или требуется внести изменение в логику, разработчик вынужден тиражировать правки во все макеты, что неизбежно ведет к рассинхронизации и возникновению новых багов.

В этой статье мы подробно разберем несколько стратегий, которые позволят вынести общую часть запроса в отдельное хранилище и динамически подключать к ней уникальные «хвосты» для каждого конкретного случая. Проанализируем как стандартные механизмы 1С, так и продвинутые архитектурные подходы.

Метод 1. Использование Менеджера временных таблиц (МВТ) в СКД

Этот способ позволяет физически разделить выполнение запроса на два этапа: сначала подготавливается общая часть, результаты которой сохраняются в памяти (или в базе данных) в виде временных таблиц, а затем эти таблицы передаются в Систему компоновки данных (СКД) как готовый источник.

Разберем этот механизм по шагам. Сначала мы создаем общий модуль или процедуру, где выполняется основной «тяжелый» блок запроса. Результат мы помещаем в объект МенеджерВременныхТаблиц. Рассмотрим пример кода:


// 1. Подготовка общей части запроса
ЗапросОбщий = Новый Запрос;
ЗапросОбщий.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
ЗапросОбщий.Текст = 
    "ВЫБРАТЬ
    |   Продажи.Номенклатура,
    |   СУММА(Продажи.Количество) КАК КолВо
    |ПОМЕСТИТЬ ВТ_ОбщиеДанные
    |ИЗ
    |   РегистрНакопления.Продажи КАК Продажи
    |СГРУППИРОВАТЬ ПО
    |   Продажи.Номенклатура";

ЗапросОбщий.Выполнить();

// 2. Инициализация СКД с передачей МВТ
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Важный момент: шестой параметр метода Инициализировать - это наш МенеджерВТ
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина, , ЗапросОбщий.МенеджерВременныхТаблиц);

В самой схеме компоновки данных (в конструкторе запроса) вам достаточно написать простой текст: ВЫБРАТЬ * ИЗ ВТ_ОбщиеДанные КАК Т. Система увидит таблицу, которая уже лежит в менеджере, и сможет с ней работать. Важно помнить: при таком подходе стандартные отборы СКД могут не «прокидываться» внутрь общего запроса автоматически, поэтому общую часть стоит проектировать с учетом максимально возможных фильтров.

Метод 2. Программная сборка текста запроса из фрагментов

Если разделение на два этапа выполнения (как в методе с МВТ) неприемлемо по соображениям производительности, мы можем использовать строковую сборку текста перед тем, как передать его в схему компоновки. Рассмотрим, как это реализовать наиболее элегантно.

Мы можем хранить общую часть в отдельном макете типа «Текст» или в общем модуле в виде строковой константы. Уникальные части («хвосты») хранятся в соответствующих макетах отчетов. Перед компоновкой мы объединяем их. Проанализируем пример функции сборки:


Функция ПолучитьПолныйТекстЗапроса(ИмяУникальногоМакета)
    
    ОбщаяЧасть = ПолучитьОбщуюЧастьЗапроса(); // Функция возвращает 900+ строк кода
    УникальныйХвост = ПолучитьМакет(ИмяУникальногоМакета).Текст;
    
    // Соединяем части. Обычно уникальный хвост начинается с выбора из ВТ, 
    // созданных в общей части.
    ПолныйТекст = ОбщаяЧасть + " ; " + Символы.ПС + УникальныйХвост;
    
    Возвращает ПолныйТекст;
КонецФункции

Главный недостаток этого метода — потеря возможности использовать конструктор запроса в СКД для финального текста. Однако мы можем обойти это ограничение, используя отладчик. Выгрузив итоговый текст в консоль запросов, мы редактируем его там, а затем снова разделяем на «голову» и «хвост».

Метод 3. Работа с объектом «Схема запроса»

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

Рассмотрим, как это работает. Мы инициализируем объект СхемаЗапроса и загружаем в него базовый текст. Затем программно добавляем новые пакеты запросов или условия:


Схема = Новый СхемаЗапроса;
Схема.УстановитьТекст(ОбщийТекст); // Загружаем 900 строк базы

// Добавляем новый пакет (хвост)
ПакетХвост = Схема.ПакетныеЗапросы.Добавить(Тип("ПакетныйЗапросВыборкаСхемыЗапроса"));
ОператорВыбора = ПакетХвост.Операторы[0];
// Здесь мы программно описываем источники и поля
// ...
ИтоговыйТекст = Схема.ПолучитьТекст();

Проанализируем преимущества: СхемаЗапроса гарантирует синтаксическую корректность итогового кода. Мы можем программно находить нужные нам временные таблицы в общем блоке и изменять их «на лету» перед выполнением.

Метод 4. Вложенные схемы компоновки данных

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

  1. Централизованное исправление: вы правите логику во вложенной схеме один раз, и изменения вступают в силу везде.
  2. Визуальное редактирование: вложенную схему можно открывать в конструкторе СКД как обычный отчет.
  3. Передача параметров: настройки и отборы основной схемы легко транслируются во вложенную через связи параметров.

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

Метод 5. Использование препроцессора (БСП-стайл)

В типовых решениях от 1С (на базе БСП) часто применяется механизм тегов в комментариях запроса. Рассмотрим пример такого подхода:


ТекстЗапроса = 
    "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ Регистр.Продажи;
    |//#{УНИКАЛЬНЫЙ_БЛОК}
    |ВЫБРАТЬ * ИЗ ВТ_Данные";

// Перед выполнением делаем замену
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "//#{УНИКАЛЬНЫЙ_БЛОК}", ТекстИзМакетаХвоста);

Это позволяет визуально видеть структуру всего запроса целиком, но при этом динамически вставлять в него специфичные куски кода в заранее определенные «точки расширения».

Выводы и рекомендации

Подведем итог нашему анализу. Выбор метода зависит от ваших приоритетов:

В любом случае, уход от прямого дублирования 900 строк кода — это важный шаг к созданию надежной и расширяемой системы. Мы рекомендуем начать с программной сборки текста, так как это дает максимальный контроль над итоговым SQL-запросом при минимальных затратах на переработку архитектуры существующих отчетов.

← На главную