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