Как работает свертка таблицы значений в 1С и сохраняется ли порядок строк?

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

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

Механизм работы метода Свернуть()

Для начала вспомним синтаксис метода. Он принимает два строковых параметра: список колонок для группировки и список колонок для суммирования. Давайте проанализируем, как система выполняет эту операцию «под капотом».

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

Однако, как справедливо замечено в обсуждении, не стоит полагаться на недокументированное поведение. Если для вашей бизнес-логики критичен порядок следования элементов, всегда выполняйте явную сортировку после завершения свертки. Посмотрим на пример кода:


// Пример стандартной свертки с последующей сортировкой
ТЗ_Данные.Свернуть("Номенклатура, Склад", "Количество, Сумма");
ТЗ_Данные.Сортировать("Номенклатура Возр, Сумма Убыв");

Потеря данных и сброс индексов

Проанализируем критически важную особенность, о которой часто забывают начинающие разработчики. Метод Свернуть() безвозвратно удаляет из таблицы те колонки, которые вы не указали в параметрах группировки или суммирования. Если в вашей таблице было 10 колонок, а вы свернули ее по двум, остальные 8 колонок будут удалены из структуры таблицы.

Также стоит учитывать работу с индексами. Если вы предварительно создавали индексы для таблицы значений через ТЗ.Индексы.Добавить() для ускорения поиска, то после вызова Свернуть() все индексы будут сброшены. Это связано с тем, что структура таблицы меняется, и старые индексы становятся неактуальными. Если после группировки вам снова нужен быстрый поиск, индексы придется пересоздать заново.

Особенности типов данных и работа с NULL

Выясним, как метод обрабатывает различные типы данных в суммируемых колонках. Метод Свернуть() корректно работает только с числовыми типами. Если в колонку для суммирования попадет строка или значение типа Дата, платформа проигнорирует их или может вызвать ошибку выполнения. Особое внимание стоит уделить значениям Null.

  1. Если Null встречается в ключевых колонках (по которым идет группировка), платформа считает все такие значения идентичными и объединяет их в одну строку.
  2. Если Null попадает в колонку суммирования, он игнорируется, и итоговая сумма будет рассчитана по остальным числовым значениям.

Альтернативные способы группировки данных

Иногда стандартный метод Свернуть() оказывается недостаточно гибким или медленным. Разберем другие способы решения задачи, которые упоминались опытными разработчиками.

Способ 1: Использование Запроса (самый эффективный)

Если объем данных в таблице велик (десятки и сотни тысяч строк), лучше всего выгрузить таблицу во временную таблицу запроса и выполнить группировку средствами SQL. Это позволяет не только суммировать, но и вычислять МАКСИМУМ, МИНИМУМ или СРЕДНЕЕ.


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

// Выгружаем имеющуюся ТЗ в запрос
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ";
Запрос.УстановитьПараметр("ТЗ", ТЗ_Данные);
Запрос.Выполнить();

// Выполняем группировку
Запрос.Текст = 
"ВЫБРАТЬ
|	ВТ.Номенклатура,
|	СУММА(ВТ.Количество) КАК Количество,
|	МАКСИМУМ(ВТ.Цена) КАК МаксЦена
|ИЗ
|	ВТ_Данные КАК ВТ
|ГРУППИРОВАТЬ ПО
|	ВТ.Номенклатура";

ТЗ_Результат = Запрос.Выполнить().Выгрузить();

Способ 2: Использование объекта «Соответствие» (Map)

Этот метод часто быстрее свертки, если вы наполняете таблицу в цикле и хотите группировать данные «на лету». Мы используем Соответствие, где ключом выступает значение группировки, а значением — структура или сама строка таблицы.


СоответствиеГрупп = Новый Соответствие;
Для Каждого СтрокаИст Из ТЗ_Источник Цикл
    Ключ = СтрокаИст.Номенклатура; // Можно использовать Структуру для составного ключа
    НайденнаяСтрока = СоответствиеГрупп.Получить(Ключ);
    
    Если НайденнаяСтрока = Неопределено Тогда
        НоваяСтрока = ТЗ_Результат.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИст);
        СоответствиеГрупп.Вставить(Ключ, НоваяСтрока);
    Иначе
        НайденнаяСтрока.Количество = НайденнаяСтрока.Количество + СтрокаИст.Количество;
    КонецЕсли;
КонецЦикла;

Способ 3: Построчный обход с поиском (не рекомендуется)

Рассмотрим ситуацию, когда программист пытается вручную перебирать таблицу и искать дубли через НайтиСтроки(). Этот способ допустим только для очень маленьких таблиц (до 100 строк). На больших массивах время выполнения будет расти в геометрической прогрессии, так как для каждой строки будет выполняться полный или частичный перебор таблицы. В 1С такой подход считается «антипаттерном».

Заключение и рекомендации

Подводя итог, можно сказать следующее: метод Свернуть() является надежным стандартом для простых операций на малых и средних объемах данных. Если вам важно сохранить порядок строк — обязательно вызывайте Сортировать() после свертки. Если же вы работаете с высоконагруженными системами или сложными вычислениями (среднее, остатки, сложные условия), используйте механизм Запросов через временные таблицы. Это обеспечит максимальную производительность и предсказуемость результата.

← На главную