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