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