Это легко и непринужденно реализуется при помощи класса ИндексированнаяТаблица
Вот код класса КроссТаблица - наследника ИТЗ.
Перем ИТЗ; //:ИндексированнаяТаблица
Перем Колонки Экспорт; //:ИндексированнаяТаблица
Перем ИзмерениеКолонки;
Функция Сам(Конт) Возврат Конт; КонецФункции
//#if DEBUG
Процедура ПриОткрытии()
Форма.Параметр._ПриОткрытии();
Форма.Закрыть();
КонецПроцедуры
//#endif
Процедура Конструктор()
ИТЗ=Сам(Контекст).ПолучитьБазовыйКласс("ИндексированнаяТаблица");
КонецПроцедуры // Конструктор
Процедура Построить(Источник,ИзмеренияСтроки,ИзмерениеКол,Ресурс) Экспорт
ИзмерениеКолонки=ИзмерениеКол;
Если ТипЗначенияСтр(Источник)="Запрос" Тогда
ИТЗ.ЗагрузитьЗапрос(Источник,0,0);
ИначеЕсли ТипЗначенияСтр(Источник)="ТаблицаЗначений" Тогда
ИТЗ.Загрузить(Источник);
Иначе
ВМ=СоздатьОбъект("ВыполняемыйМодуль");
ВМ.ВыброситьИскл("Неверно задан источник");
Возврат;
КонецЕсли;
ИТЗ.ДобавитьИндекс("Колонки",ИзмерениеКолонки);
ИТЗ.Выгрузить(Колонки,"Колонки",,1);
Колонки.ПереименоватьКолонку(ИзмерениеКолонки,"Значение");
Колонки.ДобавитьИндекс("Колонки","Значение");
КолонкиСумм=Ресурс;
Колонки.ВыбратьСтроки();
Пока Колонки.ПолучитьСтроку()=1 Цикл
ИДКолонки="_"+Колонки.НомерСтроки;
ИТЗ.НоваяКолонка(ИДКолонки);
КолонкиСумм=КолонкиСумм+","+ИДКолонки;
ИТЗ.УстановитьФильтр(Колонки.Значение,Колонки.Значение,"Колонки");
ИТЗ.ЗаполнитьКолонку("Колонки",ИДКолонки,ИТЗ,"Колонки",Ресурс);
КонецЦикла;
сзИзмеренияСтрок=СоздатьОбъект("СписокЗначений");
,""")+"""");
Для Сч=1 По сзИзмеренияСтрок.РазмерСписка() Цикл
Измерение=сзИзмеренияСтрок.ПолучитьЗначение(Сч);
ие);
КонецЦикла;
"""",""),",",";");
ИТЗ.Группировать(стрГруппировки,КолонкиСумм);
КонецПроцедуры // Построить
Функция ВыбратьКолонки() Экспорт
Возврат Колонки.ВыбратьСтроки();
КонецФункции // ВыбратьКолонки
Функция ПолучитьКолонку() Экспорт
в=Колонки.ПолучитьСтроку();
Возврат в;
КонецФункции // ПолучитьКолонку
А это пример использования - кусок кода из отчета с произвольным количеством вертикальных группировок не более 4-х и одной горизонтальной группировкой
Процедура Колонки(Табл,ИмяСекции)
ТАб.ВывестиСекцию(ИмяСекции+"|Начало");
КТ.ВыбратьКолонки();
Пока КТ.ПолучитьКолонку()=1 Цикл
К=Табл.ПолучитьЗначение(,"_"+КТ.Колонки.НомерСтроки);
ТАб.ПрисоединитьСекцию(ИмяСекции+"|Колонка");
КонецЦикла;
КонецПроцедуры // Колонки
//_____________________________________________________________________________
Процедура ВывестиГруппировку(Т,НомерСекции=1)
Т.ВыбратьСтроки();
НазваниеГруппировки=Т.ИмяКолонки(НомерСекции-4+КоличествоГруппировок);
ЭтоПоследняяГруппировка=?(Т.ИмяКолонки(Т.КоличествоКолонок())="тзПотомки",0,1);
Пока Т.ПолучитьСтроку()=1 Цикл
Наименование=Т.ПолучитьЗначение(,НазваниеГруппировки);
Колонки(Т,"Строка"+НомерСекции);
Если ЭтоПоследняяГруппировка=0 Тогда
ВывестиГруппировку(Т.тзПотомки,НомерСекции+1);
КонецЕсли;
КонецЦикла;
КонецПроцедуры // ВывестиГруппировку
Процедура Сформировать()
//...................
КТ=СоздатьОбъект("КроссТаблица");
КТ.Построить(Запрос,СтрГруппировки,"Товар","Количество");
КТ.ВыбратьСтроки();
КТ.ПолучитьСтроку();
Колонки(КТ,"Шапка");
КТ.ВыбратьСтроки();
ВывестиГруппировку(КТ,5-КоличествоГруппировок);
//..................
КонецПроцедуры