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