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