Как правильно свернуть таблицу значений с большим количеством колонок в 1С

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

В процессе разработки часто возникает задача агрегации данных в объекте ТаблицаЗначений. При работе с таблицами, содержащими десятки полей, ручное перечисление всех колонок в методе Свернуть() становится трудоемким и снижает гибкость кода. Разберем по шагам, как решить эту задачу программно, а также проанализируем альтернативные и более производительные подходы к группировке данных в платформе 1С:Предприятие.

Особенности и синтаксис метода Свернуть

Метод Свернуть() объекта ТаблицаЗначений предназначен для удаления повторяющихся строк с одновременным суммированием числовых колонок. Рассмотрим его базовый синтаксис:

ТаблицаЗначений.Свернуть(КолонкиГруппировок, КолонкиСуммирования);

Важно учитывать ключевые особенности работы данного метода:

  1. Удаление неуказанных колонок: Все колонки таблицы, которые не вошли ни в первый параметр (группировки), ни во второй (суммирование), безвозвратно удаляются из результирующей таблицы значений.
  2. Синтаксический статус: Метод Свернуть() является процедурой, изменяющей исходный объект на месте, а не функцией. Попытка присвоить результат выполнения метода переменной приведет к ошибке выполнения.
  3. Требования к типам данных: Колонки, переданные в качестве суммируемых, должны содержать исключительно числовые значения либо Неопределено/Null. Наличие строк или ссылок вызовет исключение при попытке сложения.
  4. Сортировка: В процессе работы метод переупорядочивает строки по колонкам группировки. Исходный порядок строк при этом гарантированно теряется.

Способ 1. Динамическое формирование списков колонок в коде

Синтаксис платформы не поддерживает маски вроде Свернуть("*"). Если состав колонок заранее неизвестен или слишком велик, сформируем строки параметров динамически, перебрав коллекцию колонок таблицы значений.

Разберем пример программного обхода колонок с разделением их на измерения (группировки) и ресурсы (суммирование) по типам данных:


КолонкиГруппировок = "";
КолонкиСуммирования = "";

Для Каждого Колонка Из ТЗ.Колонки Цикл
    Если Колонка.ТипЗначения.СодержитТип(Тип("Число")) Тогда
        КолонкиСуммирования = КолонкиСуммирования + ?(ПустаяСтрока(КолонкиСуммирования), "", ",") + Колонка.Имя;
    Иначе
        КолонкиГруппировок = КолонкиГруппировок + ?(ПустаяСтрока(КолонкиГруппировок), "", ",") + Колонка.Имя;
    КонецЕсли;
КонецЦикла;

// Вызываем метод как процедуру для существующей таблицы значений
ТЗ.Свернуть(КолонкиГруппировок, КолонкиСуммирования);

Такой подход позволяет корректно обработать таблицу любой структуры без жесткой привязки к именам полей.

Способ 2. Группировка на уровне запроса

В большинстве сценариев данные для таблицы значений получаются из базы с помощью запроса. Выполнять группировку средствами СУБД значительно эффективнее, чем выгружать детальные записи в память и затем сворачивать их на клиенте или сервере 1С.

Если при попытке использовать конструкцию СГРУППИРОВАТЬ ПО возникает ошибка, проанализируем ее причины:

  1. Строки неограниченной длины: Поля с неограниченной строкой нельзя группировать напрямую. Их необходимо явно привести к фиксированной длине с помощью функции ВЫРАЗИТЬ(Поле КАК Строка(1000)).
  2. Хранилища значений: Поля с типом ХранилищеЗначения не могут участвовать в операциях группировки.
  3. Составные типы: Если поле содержит составной тип, включающий негруппируемые типы, также требуется использовать функцию ВЫРАЗИТЬ.

Посмотрим на пример запроса с явным выражением типов и агрегацией:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВЫРАЗИТЬ(Таблица.Комментарий КАК Строка(250)) КАК Комментарий,
    |   Таблица.Номенклатура КАК Номенклатура,
    |   Таблица.Проект КАК Проект,
    |   СУММА(Таблица.Количество) КАК Количество,
    |   СУММА(Таблица.Сумма) КАК Сумма
    |ИЗ
    |   Документ.ЗаказПокупателя.Товары КАК Таблица
    |ГДЕ
    |   Таблица.Ссылка = &Ссылка
    |СГРУППИРОВАТЬ ПО
    |   ВЫРАЗИТЬ(Таблица.Комментарий КАК Строка(250)),
    |   Таблица.Номенклатура,
    |   Таблица.Проект";

Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
РезультатЗапроса = Запрос.Выполнить();
ТЗ = РезультатЗапроса.Выгрузить();

Способ 3. Группировка существующей таблицы через временную таблицу

Если таблица значений уже сформирована в памяти и ее структура не позволяет применить Свернуть() (например, требуется вычислить минимум, максимум или количество различных), передадим ее в запрос через менеджер временных таблиц:


Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

Запрос.Текст = 
    "ВЫБРАТЬ
    |   ТЗ.Номенклатура КАК Номенклатура,
    |   ТЗ.Склад КАК Склад,
    |   МИНИМУМ(ТЗ.НомерСтроки) КАК МинНомерСтроки,
    |   СУММА(ТЗ.Количество) КАК Количество
    |ПОМЕСТИТЬ ВТ_Данные
    |ИЗ
    |   &ТаблицаИсточник КАК ТЗ
    |СГРУППИРОВАТЬ ПО
    |   ТЗ.Номенклатура,
    |   ТЗ.Склад
    |;
    |
    |ВЫБРАТЬ
    |   ВТ.Номенклатура,
    |   ВТ.Склад,
    |   ВТ.Количество
    |ИЗ
    |   ВТ_Данные КАК ВТ
    |УПОРЯДОЧИТЬ ПО
    |   ВТ.МинНомерСтроки";

Запрос.УстановитьПараметр("ТаблицаИсточник", ИсходнаяТЗ);
РезультатТЗ = Запрос.Выполнить().Выгрузить();

Типичные ошибки при использовании метода Свернуть

Выделим распространенные ошибки, возникающие при группировке данных:

  1. Вызов метода в цепочке выражений: Конструкция ТЗ = Запрос.Выполнить().Выгрузить().Свернуть(...) приводит к ошибке Обращение к процедуре объекта как к функции. Метод Свернуть() не возвращает значение, поэтому его следует вызывать отдельной строкой.
  2. Сворачивание ДереваЗначений: Если результат запроса выгружается с параметром ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, создается объект ДеревоЗначений. У дерева значений нет метода Свернуть(), что приводит к ошибке Метод объекта не обнаружен. Для выгрузки в плоскую таблицу метод Выгрузить() следует вызывать без параметров.
  3. Потеря порядка строк: Если требуется сохранить последовательность записей (например, порядок строк исходного табличного документа), перед группировкой добавляют поле с исходным номером строки, берут по нему агрегатную функцию МИНИМУМ(НомерСтроки) в запросе и выполняют сортировку по этому полю.
← На главную