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