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

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

При разработке отчетов и обработок часто возникает задача вертикальной конкатенации: получить несколько записей из таблицы или регистра сведений и объединить их текстовые значения в одну результирующую строку через разделитель (например, "Текст1 + Текст2 + Текст3").

Разберем особенности языка запросов 1С и рассмотрим основные практические способы реализации данной задачи.

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

Проанализируем возможности стандартного языка запросов платформы 1С:Предприятие:

  1. Отсутствие агрегатной функции конкатенации: В языке запросов 1С нет прямых аналогов SQL-функций STRING_AGG, LISTAGG или GROUP_CONCAT. Оператор сложения + в запросе позволяет складывать только строковые поля в пределах одной строки, но не объединяет значения колонок между разными строками выборки при группировке.
  2. Ограничения на строки неограниченной длины: Поля неограниченной длины нельзя использовать в секциях СГРУППИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО и в условиях соединений. Для работы с ними внутри запроса требуется предварительно приводить тип с помощью конструкции ВЫРАЗИТЬ(Поле КАК СТРОКА(Длина)).

Рассмотрим основные способы объединения строк, применяемые на практике.

Способ 1. Обработка результата запроса с помощью функции СтрСоединить

Это наиболее производительный и универсальный способ для произвольного количества строк без привлечения механизмов компоновки данных. Выгрузим колонку таблицы значений в массив и объединим его функцией встроенного языка СтрСоединить.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РегистрТекст.Текст КАК Текст
    |ИЗ
    |	РегистрСведений.Текст КАК РегистрТекст
    |ГДЕ
    |	РегистрТекст.Объект = &Объект";

Запрос.УстановитьПараметр("Объект", ВыбОбъект);
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();

МассивТекстов = ТаблицаРезультата.ВыгрузитьКолонку("Текст");
ИтоговаяСтрока = СтрСоединить(МассивТекстов, " + ");

Способ 2. Последовательный обход выборки запроса

Если требуется дополнительная логика проверки каждого значения в процессе обхода, используем объект ВыборкаИзРезультатаЗапроса. Чтобы не формировать лишний разделитель в начале или конце строки, накапливаем значения в массиве либо анализируем номер итерации.

Разберем по шагам данный подход:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РегистрТекст.Текст КАК Текст
    |ИЗ
    |	РегистрСведений.Текст КАК РегистрТекст
    |ГДЕ
    |	РегистрТекст.Объект = &Объект";

Запрос.УстановитьПараметр("Объект", ВыбОбъект);
Выборка = Запрос.Выполнить().Выбрать();

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

ИтоговаяСтрока = СтрСоединить(МассивСтрок, " + ");

Способ 3. Использование функции СоединитьСтроки в СКД

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

Синтаксис функции:

СоединитьСтроки(Значение, РазделительЭлементов, РазделителиКолонок)

Параметры:

  1. Значение: Выражение, массив или таблица значений для объединения. Если передан массив, объединяются его элементы. Если таблица значений — объединяются все колонки и строки.
  2. РазделительЭлементов: Строка-разделитель между элементами (по умолчанию — символ перевода строки).
  3. РазделителиКолонок: Разделитель колонок таблицы значений (по умолчанию "; ").

Для объединения значений поля Текст в схеме компоновки данных на вкладке Ресурсы укажем выражение:

СоединитьСтроки(Массив(Текст), " + ")

Если СКД используется программно для получения итоговой таблицы без вывода в табличный документ, используем ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений:


// Предполагается, что СхемаКомпоновкиДанных и Настройки уже инициализированы
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

ТаблицаРезультат = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

Способ 4. Реализация внутри запроса через соединения (для фиксированного числа строк)

Если количество объединяемых записей заранее известно и ограничено небольшим фиксированным числом (например, не более двух или трех значений), задачу можно решить непосредственно в тексте одного запроса через левые соединения с нумерацией строк.

Рассмотрим пример, когда для объекта требуется объединить до двух строк:


ВЫБРАТЬ
	Т1.Объект КАК Объект,
	Т1.Текст КАК Текст1,
	Т2.Текст КАК Текст2,
	ЕСТЬNULL(Т1.Текст, """") + ВЫБОР
		КОГДА Т2.Текст ЕСТЬ NULL ТОГДА """"
		ИНАЧЕ "" + "" + Т2.Текст
	КОНЕЦ КАК ПолныйТекст
ИЗ
	(ВЫБРАТЬ
		Регистр.Объект КАК Объект,
		МИНИМУМ(Регистр.Текст) КАК Текст
	ИЗ
		РегистрСведений.Текст КАК Регистр
	ГДЕ
		Регистр.Объект = &Объект
	СГРУППИРОВАТЬ ПО
		Регистр.Объект) КАК Т1
	ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
		Регистр.Объект КАК Объект,
		МАКСИМУМ(Регистр.Текст) КАК Текст
	ИЗ
		РегистрСведений.Текст КАК Регистр
	ГДЕ
		Регистр.Объект = &Объект
	СГРУППИРОВАТЬ ПО
		Регистр.Объект) КАК Т2
	ПО Т1.Объект = Т2.Объект
		И Т1.Текст <> Т2.Текст

Важно: При произвольном или большом количестве строк данный метод становится громоздким и неэффективным. Для динамического набора записей рекомендуется использовать функцию СоединитьСтроки в СКД или постобработку результата методом СтрСоединить.

← На главную