Как программно выгрузить таблицу (кросс-таблицу) из СКД в Таблицу Значений?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке сложных отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с необходимостью не просто вывести данные на экран, но и получить результат в виде ТаблицыЗначений для дальнейшего программного анализа. Однако, если структура отчета в СКД представляет собой «Таблицу» (с группировками как по строкам, так и по колонкам) или «Диаграмму», стандартный метод выгрузки выдает ошибку: «Не поддерживается вывод таблиц и диаграмм в универсальную коллекцию значений».

В этой статье мы подробно разберем, почему возникает эта проблема, и рассмотрим несколько эффективных способов её решения.

Выясним причину: почему стандартный метод не работает?

Проанализируем работу штатного механизма компоновки. Когда мы используем ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений, платформа ожидает линейную или иерархическую структуру данных. ТаблицаЗначений в 1С — это плоская структура с фиксированным набором колонок. ДеревоЗначений добавляет иерархию строк, но все еще требует заранее определенных колонок.

Объект «Таблица» в СКД — это по сути динамическая кросс-таблица. Количество её колонок заранее неизвестно и зависит от того, какие данные попадут в выборку по группировкам колонок. Поскольку процессор вывода в коллекцию не умеет «на лету» динамически создавать колонки в ТаблицеЗначений для каждого нового значения группировки колонок, платформа блокирует эту операцию на уровне ядра.

Способ №1: Использование промежуточного Табличного Документа

Это самый простой и часто используемый метод. Суть заключается в том, чтобы вывести результат в невидимый ТабличныйДокумент, а затем прочитать его ячейки. Рассмотрим этот процесс по шагам.

Во-первых, выполним стандартную компоновку в табличный документ:


ТабДок = Новый ТабличныйДокумент;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Используем стандартный генератор макета для табдока
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиСКД, , , Тип("ГенераторМакетаКомпоновкиДанных"));

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

Во-вторых, когда ТабДок заполнен, мы можем перебрать его области. Основная сложность здесь — точно определить, какие ячейки соответствуют группировкам, а какие — ресурсам. Этот метод отлично подходит, если структура таблицы фиксирована по смыслу, но не подходит для высокопроизводительных вычислений из-за затрат на формирование графического представления.

Способ №2: Ручной перебор через Процессор Компоновки Данных

Этот метод является наиболее «профессиональным» и гибким, так как позволяет перехватывать данные до того, как они будут превращены в визуальные элементы. Мы будем использовать метод Следующий() объекта ПроцессорКомпоновкиДанных.

Проанализируем ситуацию: процессор выдает элементы нескольких типов: НачалоГруппировки, КонецГруппировки и Записи. Нам нужно самостоятельно отслеживать, когда начинается «колонка», а когда «строка».


ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

ТЗ_Результат = Новый ТаблицаЗначений;
// Здесь нужно предварительно добавить колонки, если они известны, 
// либо добавлять их динамически при чтении типа "НачалоГруппировки"

Пока Истина Цикл
    ЭлементРезультата = ПроцессорКомпоновки.Следующий();
    Если ЭлементРезультата = Неопределено Тогда
        Прервать;
    КонецЕсли;

    // Проверяем тип элемента компоновки
    Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НачалоГруппировки Тогда
        // Логика обработки начала строки или колонки
    ИначеЕсли ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.Записи Тогда
        // Логика получения значений ресурсов
        НоваяСтрокаТЗ = ТЗ_Результат.Добавить();
        Для Каждого ЗначениеПараметра Из ЭлементРезультата.ЗначенияПараметров Цикл
            // Заполнение колонок ТЗ
        КонецЦикла;
    КонецЕсли;
КонецЦикла;

Этот способ требует написания собственного алгоритма «разворота» (pivot) таблицы, зато он работает максимально быстро и не ограничен визуальными рамками табличного документа.

Способ №3: Выгрузка «плоского списка» с последующим разворотом

Если нам необходимо получить данные кросс-таблицы в ТаблицуЗначений, мы можем пойти на хитрость: изменить настройки СКД программно перед формированием. Вместо структуры «Таблица» мы создадим структуру «Список», где в группировки строк добавим и те поля, которые должны были быть колонками.

Разберем алгоритм действий:

  1. Программно заменяем структуру настроек СКД на детальные записи или простые группировки.
  2. Выгружаем результат в плоскую ТаблицуЗначений стандартным ГенераторомМакетаКомпоновкиДанныхДляКоллекцииЗначений.
  3. Используем метод ТЗ.Скопировать() и программный перебор для трансформации плоской таблицы в двумерную.

Пример программного изменения структуры для получения плоской таблицы:


Настройки = КомпоновщикНастроек.ПолучитьНастройки();
Настройки.Структура.Очистить();

НоваяГруппировка = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
НоваяГруппировка.Использование = Истина;

// Добавляем все нужные поля (и строк, и колонок) в выбранные поля этой группировки
ВыбранноеПоле = НоваяГруппировка.ВыбранныеПоля.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПоле.Поле = Новый ПолеКомпоновкиДанных("Номенклатура");
ВыбранноеПоле.Использование = Истина;

ВыбранноеПолеК = НоваяГруппировка.ВыбранныеПоля.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеК.Поле = Новый ПолеКомпоновкиДанных("Склад");
ВыбранноеПолеК.Использование = Истина;

После получения такой «плоской» таблицы, мы можем легко развернуть склады в колонки, используя метод ТЗ.Колонки.Добавить() для каждого уникального склада.

Подведем итоги

Мы рассмотрели проблему невозможности прямой выгрузки таблиц СКД в коллекции значений. Важно запомнить: штатный ГенераторМакета...ДляКоллекцииЗначений работает только с линейными структурами.

Выбор решения зависит от ваших целей:

  1. Если важна простота реализации — используйте вывод в невидимый ТабличныйДокумент.
  2. Если важна производительность — используйте прямой перебор через ПроцессорКомпоновкиДанных.Следующий().
  3. Если нужно минимум кода для трансформации — выгружайте плоский список и разворачивайте его методами работы с ТаблицейЗначений.

Использование этих подходов позволит вам эффективно обходить системные ограничения платформы 1С и использовать всю мощь СКД для подготовки данных любой сложности.

← На главную