Как сгруппировать записи и объединить строки через запятую в 1С?

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

При разработке отчетов и обработок часто возникает задача свернуть несколько повторяющихся записей в одну, сцепив их текстовые значения в единую строку через запятую или другой разделитель. Рассмотрим, как решить эту задачу в платформе 1С, изучим ограничения языка запросов и разберем практические способы реализации.

Ограничения языка запросов 1С

Выясним сразу: в самом языке запросов 1С отсутствуют встроенные агрегатные функции для склеивания строк из разных записей одной группировки (такие как GROUP_CONCAT или STRING_AGG в классическом SQL). Стандартный оператор + позволяет объединять только значения колонок одной текущей записи.

Сгруппировать строки непосредственно в тексте запроса без использования дополнительных механизмов не получится. Однако мы можем воспользоваться альтернативными решениями: Системой компоновки данных (СКД), программной постобработкой выборки или специальными конструкциями языка запросов.

Решение 1. Использование функции СоединитьСтроки() в СКД

Самым простым и быстрым способом агрегации строк является использование встроенной функции языка выражений СКД СоединитьСтроки(). Данная функция доступна на вкладках Вычисляемые поля и Ресурсы.

Проанализируем порядок настройки отчета в СКД по шагам:

  1. В запросе набора данных получаем детальные записи (например, контрагента и его свойства).
  2. Переходим на вкладку Ресурсы.
  3. Для поля, значения которого нужно объединить (например, Свойство), указываем формулу ресурса: СоединитьСтроки(Свойство, ", ")
  4. Если необходимо предварительно отсортировать или отфильтровать элементы, используем более комплексное выражение с функциями работы с массивами: СоединитьСтроки(Массив(Свойство), ", ")

Важное условие: чтобы платформа смогла правильно сворачивать данные, объединяемое поле не должно присутствовать в самом списке полей группировки отчета. Оно должно выводиться исключительно как ресурс для основной группировки.

Решение 2. Программная обработка результата запроса в коде

Если задача выполняется во встроенном языке без применения СКД, сгруппировать данные можно путем обхода выборки запроса. Разберем по шагам наиболее оптимальный алгоритм:

  1. Выполняем запрос для получения детальных записей с необходимым порядком сортировки.
  2. Создаем массив для накапливания подчиненных значений текущей группировки.
  3. Используем функцию СтрСоединить() для превращения элементов массива в единую строку.

Посмотрим на пример реализации алгоритма:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТК.Контрагент КАК Контрагент,
    |	ТК.Свойство КАК Свойство
    |ИЗ
    |	РегистрСведений.ЗначенияСвойств КАК ТК
    |УПОРЯДОЧИТЬ ПО
    |	Контрагент";

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

ТаблицаИтогов = Новый ТаблицаЗначений;
ТаблицаИтогов.Колонки.Добавить("Контрагент");
ТаблицаИтогов.Колонки.Добавить("СписокСвойств");

ТекущийКонтрагент = Неопределено;
МассивСвойств = Новый Массив;

Пока Выборка.Следующий() Цикл
    Если Выборка.Контрагент <> ТекущийКонтрагент Тогда
        Если ТекущийКонтрагент <> Неопределено Тогда
            НоваяСтрока = ТаблицаИтогов.Добавить();
            НоваяСтрока.Контрагент = ТекущийКонтрагент;
            НоваяСтрока.СписокСвойств = СтрСоединить(МассивСвойств, ", ");
        КонецЕсли;
        
        ТекущийКонтрагент = Выборка.Контрагент;
        МассивСвойств.Очистить();
    КонецЕсли;
    
    МассивСвойств.Добавить(Строка(Выборка.Свойство));
КонецЦикла;

Если ТекущийКонтрагент <> Неопределено Тогда
    НоваяСтрока = ТаблицаИтогов.Добавить();
    НоваяСтрока.Контрагент = ТекущийКонтрагент;
    НоваяСтрока.СписокСвойств = СтрСоединить(МассивСвойств, ", ");
КонецЕсли;

Совет по производительности: избегайте склеивания строк в цикле оператором + (например, Строка = Строка + ", " + НовоеЗначение). Это приводит к постоянному перераспределению памяти. Накапливание элементов в Массив с последующим вызовом СтрСоединить() работает значительно быстрее.

Решение 3. Левые соединения в запросе (для фиксированного количества элементов)

Рассмотрим ситуативный вариант: если заранее известно, что максимальное количество объединяемых свойств для одной группировки строго ограничено (например, не более 2–3 элементов), объединить их можно прямо в запросе с помощью левых соединений таблицы с самой собой.

Проанализируем пример соединения по порядковому номеру или условию:


ВЫБРАТЬ
	Т1.Контрагент КАК Контрагент,
	ЕСТЬNULL(Т1.Свойство, "") 
		+ ВЫБОР КОГДА Т2.Свойство ЕСТЬ НЕ NULL ТОГДА ", " + Т2.Свойство ИНАЧЕ "" КОНЕЦ КАК СписокСвойств
ИЗ
	ИсходныеДанные КАК Т1
	ЛЕВОЕ СОЕДИНЕНИЕ ИсходныеДанные КАК Т2
		ПО Т1.Контрагент = Т2.Контрагент И Т1.НомерЗаписи = 1 И Т2.НомерЗаписи = 2
ГДЕ
	Т1.НомерЗаписи = 1

Этот способ подходит для узкого круга задач, но при произвольном количестве подчиненных записей следует отдавать предпочтение решению через СКД или программную обработку массива.

← На главную