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