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