При разработке сложных отчетов в системе компоновки данных (СКД) часто возникает задача: реализовать в рамках одного объекта метаданных несколько вариантов отчета, которые должны получать данные из принципиально разных источников. Несмотря на то, что результирующие поля могут совпадать, логика получения данных в запросах может существенно различаться. В этой статье мы подробно разберем несколько эффективных способов решения этой задачи, проанализируем их преимущества и возможные сложности.
Этот метод считается наиболее гибким и "чистым" с точки зрения архитектуры 1С. Мы не пытаемся уместить "несовместимое" в одну схему, а подкладываем компоновщику нужный макет в зависимости от выбора пользователя. Рассмотрим этот процесс по шагам.
Во-первых, создадим в дереве метаданных отчета несколько макетов типа Схема компоновки данных. Например, ОсновнаяСхемаКомпоновкиДанных и ДополнительнаяСхема. В каждой схеме настроим свои наборы данных.
Во-вторых, обратимся к модулю объекта отчета и переопределим стандартную процедуру ПриКомпоновкеРезультата. Разберем пример кода:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Определяем, какой вариант выбрал пользователь
ИмяВарианта = ЭтотОбъект.ТекущийВариантНастройки;
Если ИмяВарианта = "ВариантСНабором1" Тогда
СхемаДляРаботы = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
ИначеЕсли ИмяВарианта = "ВариантСНабором2" Тогда
СхемаДляРаботы = ПолучитьМакет("ДополнительнаяСхема");
КонецЕсли;
// Важный нюанс: нужно инициализировать компоновщик под новую схему
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаДляРаботы));
// Загружаем настройки выбранного варианта
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Выполняем стандартную компоновку с новой схемой
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаДляРаботы, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Важный момент: при использовании этого метода необходимо помнить, что КомпоновщикНастроек по умолчанию привязан к основной схеме. Если вы просто подмените схему, но не вызовете метод Инициализировать, настройки отборов и группировок могут "слететь" или вызвать ошибку несовместимости полей.
Если вы не хотите писать много кода и предпочитаете работать в конструкторе СКД, можно объединить два разных запроса в один набор данных типа "Запрос", используя оператор ОБЪЕДИНИТЬ ВСЕ. Чтобы при выборе определенного варианта выполнялся только нужный запрос, мы добавим специальные параметры-условия.
Проанализируем структуру такого запроса:
ВЫБРАТЬ
Поле1, Поле2, Поле3
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
&РежимОтчета = 1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Поле1, Поле2, Поле3
ИЗ
РегистрНакопления.Закупки КАК Закупки
ГДЕ
&РежимОтчета = 2
В настройках СКД на закладке "Параметры" для Варианта 1 мы жестко устанавливаем значение параметра &РежимОтчета равным 1, а для Варианта 2 — равным 2. Обязательно установите флаг "Ограничение доступности", чтобы пользователь не мог изменить этот параметр вручную.
Выясним причину эффективности этого метода: современные СУБД (например, MS SQL Server) при получении условия ГДЕ 1 = 2 (которое получится, если параметр не совпадает) оптимизируют план запроса таким образом, что "ложная" ветка объединения даже не будет считывать данные с диска. Это гарантирует высокую производительность даже при огромных объемах данных.
Рассмотрим ситуацию, когда в одной схеме СКД создано два независимых набора данных (например, НаборДанных1 и НаборДанных2), и они не связаны между собой на закладке "Связи наборов данных".
Система СКД работает по принципу "ленивых вычислений". Если в настройках конкретного варианта в разделе "Выбранные поля", "Отборы" или "Группировки" не задействовано ни одно поле из НаборДанных2, то СКД не будет выполнять запрос к этому набору. Это позволяет нам:
Предупреждение: Будьте внимательны с общими отборами отчета. Если отбор наложен на весь отчет и включает поле, которое есть только в одном из наборов, СКД может попытаться выполнить оба запроса или выдать ошибку. Старайтесь накладывать специфичные отборы на уровне конкретных группировок варианта.
Этот способ удобен, если логика второго набора данных очень сложна и вы хотите сохранить ее автономность. Мы можем использовать механизм Вложенных схем.
Разберем алгоритм действий:
Этот метод позволяет полностью изолировать настройки одного варианта от другого, так как вложенная схема живет по своим правилам компоновки. Однако помните о передаче параметров: если во вложенную схему нужно прокинуть даты периода или организацию из основной схемы, это настраивается в таблице "Параметры" вложенной схемы в строке соответствия параметров.
Посмотрим на ситуацию, предложенную опытными разработчиками: использование типа набора данных Объединение в самом дереве наборов СКД. Внутри него можно создать Набор1 и Набор2. Чтобы разделить их по вариантам, добавим в каждый набор вычисляемое поле-константу, например, поле ТипДанных.
В Наборе1 в тексте запроса добавим "Набор1" КАК ТипДанных, а во втором — "Набор2" КАК ТипДанных. Теперь в настройках Варианта 1 мы просто добавляем фиксированный отбор: ТипДанных Равно "Набор1". СКД сама оптимизирует запросы так, чтобы получать данные только из нужной ветки объединения.
Подведем итоги нашего анализа. Выбор метода зависит от сложности вашей задачи:
Используя эти подходы, мы можем создавать многофункциональные отчеты, которые выглядят для пользователя как единый инструмент, но скрывают внутри себя сложную и оптимизированную логику получения данных из различных источников системы 1С.