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