Как программно переформатировать таблицу значений в кросс-таблицу на управляемой форме 1С?

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает классическая задача: преобразовать "плоскую" таблицу (например, Номенклатура, Характеристика, Количество) в кросс-таблицу, где значения характеристик становятся заголовками колонок. Это необходимо для наглядного отображения данных пользователю или для формирования сложных отчетов. В этой статье мы подробно разберем несколько способов решения этой задачи: от ручного перебора до использования мощных встроенных инструментов, таких как СКД и Сводные таблицы.

Способ 1. Программное добавление динамических колонок в таблицу значений

Рассмотрим самый очевидный, но трудоемкий метод — создание новой таблицы значений в памяти и заполнение её путем обхода исходных данных. Основная сложность здесь заключается в том, что в качестве имен колонок ТаблицаЗначений нельзя использовать произвольные строки (например, названия характеристик с пробелами или спецсимволами). Поэтому мы разделим внутреннее имя колонки и её заголовок.

Проанализируем алгоритм действий:

  1. Выгрузим уникальный список характеристик для формирования будущих колонок.
  2. Создадим новую таблицу и добавим в неё базовые колонки (например, Номенклатура).
  3. Добавим динамические колонки, используя префиксы для имен и оригинальные названия для заголовков.
  4. Заполним таблицу данными с помощью поиска строк или соответствий.

Посмотрим на пример кода, реализующего этот подход:


// 1. Получаем уникальные характеристики
КолонкиХарактеристик = ТвояТаблица.Выгрузить();
КолонкиХарактеристик.Свернуть("Характеристика");

ТЗ_Результат = Новый ТаблицаЗначений;
ТЗ_Результат.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

// 2. Добавляем колонки динамически
Счетчик = 1;
СоответствиеКолонок = Новый Соответствие; // Для связи Характеристика -> ИмяКолонки
Для Каждого СтрИз КолонкиХарактеристик Цикл
    ИмяКолонки = "Кол_" + Счетчик;
    ТЗ_Результат.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"), СтрИз.Характеристика);
    СоответствиеКолонок.Вставить(СтрИз.Характеристика, ИмяКолонки);
    Счетчик = Счетчик + 1;
КонецЦикла;

// 3. Заполняем данными
ИсходныеДанныеСвернуты = ТвояТаблица.Выгрузить();
ИсходныеДанныеСвернуты.Свернуть("Номенклатура");

Для Каждого СтрНом Из ИсходныеДанныеСвернуты Цикл
    НовСтр = ТЗ_Результат.Добавить();
    НовСтр.Номенклатура = СтрНом.Номенклатура;
    
    // Ищем все записи по этой номенклатуре в исходной таблице
    ПараметрыОтбора = Новый Структура("Номенклатура", СтрНом.Номенклатура);
    НайденныеСтроки = ТвояТаблица.НайтиСтроки(ПараметрыОтбора);
    
    Для Каждого СтрокаДанных Из НайденныеСтроки Цикл
        ИмяКолонки = СоответствиеКолонок.Получить(СтрокаДанных.Характеристика);
        Если ИмяКолонки <> Неопределено Тогда
            НовСтр[ИмяКолонки] = СтрокаДанных.Количество;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Важное примечание для управляемых форм: если вам нужно отобразить эту таблицу на форме, простого создания объекта ТаблицаЗначений недостаточно. Вам потребуется использовать метод ИзменитьРеквизиты для добавления реквизитов формы и метод Элементы.Добавить для создания визуальных колонок в таблице на форме.

Способ 2. Использование Системы Компоновки Данных (СКД)

Использование СКД — это более профессиональный и гибкий подход. Он позволяет избежать ручного написания алгоритмов группировки и суммирования. Мы можем программно создать схему компоновки, указать в качестве источника нашу таблицу значений (используя НаборДанныхОбъектСхемыКомпоновкиДанных) и вывести результат в ТабличныйДокумент.

Выясним причину, по которой этот метод предпочтителен: СКД сама умеет строить кросс-таблицы (матрицы), где в строках будет номенклатура, а в колонках — характеристики. Разберем по шагам создание такой схемы в коде:


Процедура СформироватьЧерезСКД(ИсходнаяТЗ)
    Схема = Новый СхемаКомпоновкиДанных;
    
    // Создаем источник данных
    Источник = Схема.ИсточникиДанных.Добавить();
    Источник.Имя = "Источник1";
    Источник.ТипИсточникаДанных = "Local";
    
    // Набор данных - объект (наша ТЗ)
    НаборДанных = Схема.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
    НаборДанных.Имя = "НаборДанных1";
    НаборДанных.ИмяОбъекта = "ВнешняяТЗ";
    НаборДанных.ИсточникДанных = "Источник1";
    
    // Добавляем поля (Номенклатура, Характеристика, Количество)
    ПолеНом = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
    ПолеНом.Поле = "Номенклатура";
    ПолеНом.ПутьКДанным = "Номенклатура";
    
    ПолеХар = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
    ПолеХар.Поле = "Характеристика";
    ПолеХар.ПутьКДанным = "Характеристика";
    
    ПолеКол = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
    ПолеКол.Поле = "Количество";
    ПолеКол.ПутьКДанным = "Количество";
    
    // Настраиваем структуру: Таблица (Строки = Номенклатура, Колонки = Характеристика)
    Настройки = Схема.НастройкиПоУмолчанию;
    Таблица = Настройки.Структура.Добавить(Тип("ТаблицаКомпоновкиДанных"));
    
    ГруппировкаСтроки = Таблица.Строки.Добавить();
    ГруппировкаСтроки.ПолеГруппировки = Новый ПолеКомпоновкиДанных("Номенклатура");
    
    ГруппировкаКолонки = Таблица.Колонки.Добавить();
    ГруппировкаКолонки.ПолеГруппировки = Новый ПолеКомпоновкиДанных("Характеристика");
    
    // Добавляем ресурс
    Ресурс = Схема.Ресурсы.Добавить();
    Ресурс.ПутьКДанным = "Количество";
    Ресурс.Выражение = "Сумма(Количество)";
    
    // Вывод в ТабДок
    ДанныеДляСКД = Новый Структура("ВнешняяТЗ", ИсходнаяТЗ);
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    Макет = КомпоновщикМакета.Выполнить(Схема, Настройки);
    
    ПроцессорКД = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКД.Инициализировать(Макет, ДанныеДляСКД);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(РезультатТабДок);
    ПроцессорВывода.Вывести(ПроцессорКД);
КонецПроцедуры

Способ 3. Использование объекта "СводнаяТаблица"

Объект СводнаяТаблица — это мощный интерактивный инструмент, который часто используется в отчетах. Его можно программно инициализировать результатами запроса или данными из ПостроительОтчета.

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


// Предположим, ТабличнаяЧасть1 - это ваша исходная ТЗ
Ист = Новый ОписаниеИсточникаДанных;
Ист.ИсточникДанных = ТабличнаяЧасть1;
Ист.Колонки.Характеристика.Измерение = Истина;
Ист.Колонки.Номенклатура.Измерение = Истина;
Ист.Колонки.Количество.Итог = "Сумма(Количество)";

Постр = Новый ПостроительОтчета;
Постр.ИсточникДанных = Ист;
Постр.Выполнить();

// Выводим в поле табличного документа на форме
ТабДок = Элементы.ПолеТабличногоДокумента1;
ТабДок.ВстроенныеТаблицы.Очистить();
СводТаб = ТабДок.ВстроенныеТаблицы.Добавить(Тип("СводнаяТаблица"));
СводТаб.ИсточникДанных = Постр;

// Настраиваем измерения и данные
СводТаб.Строки.Добавить(СводТаб.Поля.Номенклатура);
СводТаб.Колонки.Добавить(СводТаб.Поля.Характеристика);
СводТаб.Данные.Добавить(СводТаб.Поля.Количество);

// Чтобы убрать итоги, если они не нужны
СводТаб.ОтображатьПодведениеИтогов = Ложь;

Как отключить итоги в Сводной таблице? Как показано выше, свойство ОтображатьПодведениеИтогов позволяет скрыть общие результаты. Если же нужно убрать итоги только по конкретным полям, следует обращаться к свойствам этих полей в коллекциях Строки или Колонки и устанавливать свойство АвтоВидИтогов в значение Ложь.

Резюме и рекомендации

Выбор метода зависит от ваших конечных целей:

Мы рассмотрели основные инструменты для трансформации данных. Каждый из них по-своему эффективен, и понимание принципов их работы поможет вам выбирать оптимальное решение для задач любой сложности.

← На главную