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