В процессе разработки часто возникает задача агрегации данных в объекте ТаблицаЗначений. При работе с таблицами, содержащими десятки полей, ручное перечисление всех колонок в методе Свернуть() становится трудоемким и снижает гибкость кода. Разберем по шагам, как решить эту задачу программно, а также проанализируем альтернативные и более производительные подходы к группировке данных в платформе 1С:Предприятие.
Метод Свернуть() объекта ТаблицаЗначений предназначен для удаления повторяющихся строк с одновременным суммированием числовых колонок. Рассмотрим его базовый синтаксис:
ТаблицаЗначений.Свернуть(КолонкиГруппировок, КолонкиСуммирования);
Важно учитывать ключевые особенности работы данного метода:
Свернуть() является процедурой, изменяющей исходный объект на месте, а не функцией. Попытка присвоить результат выполнения метода переменной приведет к ошибке выполнения.Неопределено/Null. Наличие строк или ссылок вызовет исключение при попытке сложения.Синтаксис платформы не поддерживает маски вроде Свернуть("*"). Если состав колонок заранее неизвестен или слишком велик, сформируем строки параметров динамически, перебрав коллекцию колонок таблицы значений.
Разберем пример программного обхода колонок с разделением их на измерения (группировки) и ресурсы (суммирование) по типам данных:
КолонкиГруппировок = "";
КолонкиСуммирования = "";
Для Каждого Колонка Из ТЗ.Колонки Цикл
Если Колонка.ТипЗначения.СодержитТип(Тип("Число")) Тогда
КолонкиСуммирования = КолонкиСуммирования + ?(ПустаяСтрока(КолонкиСуммирования), "", ",") + Колонка.Имя;
Иначе
КолонкиГруппировок = КолонкиГруппировок + ?(ПустаяСтрока(КолонкиГруппировок), "", ",") + Колонка.Имя;
КонецЕсли;
КонецЦикла;
// Вызываем метод как процедуру для существующей таблицы значений
ТЗ.Свернуть(КолонкиГруппировок, КолонкиСуммирования);
Такой подход позволяет корректно обработать таблицу любой структуры без жесткой привязки к именам полей.
В большинстве сценариев данные для таблицы значений получаются из базы с помощью запроса. Выполнять группировку средствами СУБД значительно эффективнее, чем выгружать детальные записи в память и затем сворачивать их на клиенте или сервере 1С.
Если при попытке использовать конструкцию СГРУППИРОВАТЬ ПО возникает ошибка, проанализируем ее причины:
ВЫРАЗИТЬ(Поле КАК Строка(1000)).ХранилищеЗначения не могут участвовать в операциях группировки.ВЫРАЗИТЬ.Посмотрим на пример запроса с явным выражением типов и агрегацией:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Таблица.Комментарий КАК Строка(250)) КАК Комментарий,
| Таблица.Номенклатура КАК Номенклатура,
| Таблица.Проект КАК Проект,
| СУММА(Таблица.Количество) КАК Количество,
| СУММА(Таблица.Сумма) КАК Сумма
|ИЗ
| Документ.ЗаказПокупателя.Товары КАК Таблица
|ГДЕ
| Таблица.Ссылка = &Ссылка
|СГРУППИРОВАТЬ ПО
| ВЫРАЗИТЬ(Таблица.Комментарий КАК Строка(250)),
| Таблица.Номенклатура,
| Таблица.Проект";
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
РезультатЗапроса = Запрос.Выполнить();
ТЗ = РезультатЗапроса.Выгрузить();
Если таблица значений уже сформирована в памяти и ее структура не позволяет применить Свернуть() (например, требуется вычислить минимум, максимум или количество различных), передадим ее в запрос через менеджер временных таблиц:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.Номенклатура КАК Номенклатура,
| ТЗ.Склад КАК Склад,
| МИНИМУМ(ТЗ.НомерСтроки) КАК МинНомерСтроки,
| СУММА(ТЗ.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &ТаблицаИсточник КАК ТЗ
|СГРУППИРОВАТЬ ПО
| ТЗ.Номенклатура,
| ТЗ.Склад
|;
|
|ВЫБРАТЬ
| ВТ.Номенклатура,
| ВТ.Склад,
| ВТ.Количество
|ИЗ
| ВТ_Данные КАК ВТ
|УПОРЯДОЧИТЬ ПО
| ВТ.МинНомерСтроки";
Запрос.УстановитьПараметр("ТаблицаИсточник", ИсходнаяТЗ);
РезультатТЗ = Запрос.Выполнить().Выгрузить();
Выделим распространенные ошибки, возникающие при группировке данных:
ТЗ = Запрос.Выполнить().Выгрузить().Свернуть(...) приводит к ошибке Обращение к процедуре объекта как к функции. Метод Свернуть() не возвращает значение, поэтому его следует вызывать отдельной строкой.ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, создается объект ДеревоЗначений. У дерева значений нет метода Свернуть(), что приводит к ошибке Метод объекта не обнаружен. Для выгрузки в плоскую таблицу метод Выгрузить() следует вызывать без параметров.МИНИМУМ(НомерСтроки) в запросе и выполняют сортировку по этому полю.