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




А зачем? Всегда можно оперировать копией ТЗ.
Можно. Только копия ресурс кушает, если большая, и «оперировать», т.е. искать даже по индексированной — иногда скучное дело. Я всего лишь показал альтернативу, когда «всё в одном». ))
жениться тебе надо
тогда будет жаль времени на всякую ненужную ботву
Как пример простой программной работы с СКД очень хорошо. Стоило преподносить публикацию именно как пример работы с СКД, тогда польза от нее очевидна.
Смысл тогда сворачивать? Если нужны списки, так и надо в 3-й колонке значением список делать
(3) Позвольте представить, моя жена: — и уже восемь лет вместе )))
(5) Смысл простой — и свернуть надо, и данные не потерять. А список или массив хороши, когда такая колонка одна. Если было 10 колонок, по 1-й и 3-й свернули, пятую суммировали, то, когда нужны все остальные, подтаблица удобнее списка.
честно говоря, пока для себя не вижу практического применения данного решения
если я что-то сворачиваю, я это сворачиваю. Если не надо сворачивать, я не сворачиваю.
Но всё же плюс, за конструктивные ответы (и красивую жену 🙂 )
В семерки часто сталкиваюсь с такой задачей. Что нужно данные сохранять, после свертки. В частности при формировании группировок в отчетах. Но, ИМХО, в такой ситуации, лучше, действительно, оперировать таблицей значений. А уж если ресурсы жалко (когда, например, нужно работать с 100500 записями). Лучше использовать временные таблицы.
(7) Мне часто приходится сталкиваться, раньше делал через 2 таблицы (свёрнутая и исходная), но оперативку жалко. А так пыхтит сервер приложения, насколько я понял распределение нагрузки. И что-то мне подсказывает, что напрячь механизм СКД в этом случае более экономно, нежели крутить временные таблицы.
А если честно, просто захотелось побаловаться с этими функциями СКД, и всё ))
не смотря на комментарии, для меня всё равно полезно было ознакомиться, спасибо
(10) TrinitronOTV, Кто к нам пожаловал…
(0) СКДиПостроители — это откуда? не встречал такого модуля.
(0) Присоединяюсь к (12)
Если это твой модуль, было бы логично выложить и его (в части, касающейся данного решения).
Ёлы-палы, сколько ж я ещё на эти грабли наступать буду… Ща, выложу нужные функции.
ок, ПоместитьРезультатСКДвТаблицуЗначений() уже есть, но нужна еще ПолучитьОписаниеТипаБезПустых()
(15) Она совсем простая и необязательная:
Функция ПолучитьОписаниеТипаБезПустых(рОписТипов) Экспорт
мТипов=Новый Массив;
Для каждого рТип Из рОписТипов.Типы() Цикл
Если рТип=Тип(«Неопределено») или рТип=Тип(«NULL») или рТип=Неопределено или рТип=Null Тогда Продолжить КонецЕсли;
мТипов.Добавить(рТип);
КонецЦикла;
Возврат Новый ОписаниеТипов(мТипов,рОписТипов.КвалификаторыЧисла,рОписТипов.КвалификаторыСтроки,рОписТипов.КвалификаторыДаты);
КонецФункции
(0)
Вот именно за это плюс и поставлю 😉
не поняда. Зачем?