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