В практике разработчика 1С часто возникает задача: преобразовать вертикальный набор данных (строки таблицы) в одну горизонтальную строку с разделителями (например, через точку с запятой). В стандартном SQL для этого существуют функции типа GROUP_CONCAT или STRING_AGG, однако в языке запросов 1С подобные агрегатные функции для строк отсутствуют. Это связано с архитектурными ограничениями платформы, стремящейся к универсальности работы с различными СУБД (MS SQL, PostgreSQL, Oracle, IBM DB2).
В этой статье мы подробно проанализируем три основных подхода к решению этой задачи: от простого программного перебора до сложного «хакерского» метода реализации логики объединения прямо в тексте запроса.
Это самый надежный и часто используемый метод. Если вам не нужно выводить результат в динамический список или использовать склеенную строку в дальнейших соединениях внутри того же запроса, лучше всего выполнить обработку на языке 1С. Рассмотрим, как это реализовать максимально эффективно.
Проанализируем пример кода:
// Выполняем запрос для получения данных
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
ТекстРезультат = "";
Разделитель = "; ";
Пока Выборка.Следующий() Цикл
// Добавляем разделитель, если строка уже не пустая
ТекстРезультат = ТекстРезультат + ?(ПустаяСтрока(ТекстРезультат), "", Разделитель) + Выборка.Наименование;
КонецЦикла;
Преимущества: Простота реализации, отсутствие ограничений на длину строки, высокая скорость работы на небольших объемах данных. Мы полностью контролируем процесс форматирования.
Если задача стоит в рамках формирования отчета или программной работы с компоновщиком, мы можем воспользоваться мощной встроенной функцией СоединитьСтроки(). Рассмотрим ее синтаксис подробнее.
В СКД на закладке "Вычисляемые поля" или в "Ресурсах" можно указать следующее выражение:
СоединитьСтроки(Выражение, Разделитель, Порядок)
Разберем параметры по шагам:
Номенклатура.Наименование)."; ").Дата Возникновения Возр).Эта функция работает на уровне процессора компоновки. Платформа сначала получает все записи из СУБД, а затем самостоятельно агрегирует их в памяти перед выводом пользователю. Это идеальный вариант для отчетов.
Иногда возникает экстремальная потребность: получить склеенную строку в динамическом списке или внутри вложенного запроса, где нет доступа к коду 1С или СКД. Проанализируем концепцию «Агрегатного суммирования строк», предложенную опытными разработчиками сообщества. Этот метод основан на использовании бинарного дерева конкатенации.
Выясним причину, почему это сложно: в запросе 1С мы не можем организовать цикл. Однако мы можем организовать последовательные соединения таблиц. Если мы будем соединять строки попарно (1+2, 3+4, 5+6), а затем результаты этих соединений снова попарно, мы получим логарифмическую зависимость глубины соединений от количества строк.
Рассмотрим пример реализации такого запроса для объединения данных из временной таблицы Дано (с колонкой а):
// 1. Сначала нумеруем строки через соединение таблицы саму с собой
ВЫБРАТЬ
Т1.Наименование КАК Значение,
КОЛИЧЕСТВО(Т2.Наименование) КАК НомерСтроки
ПОМЕСТИТЬ ПронумерованныеСтроки
ИЗ
ВТ_Данные КАК Т1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
ПО Т1.Наименование >= Т2.Наименование
СГРУППИРОВАТЬ ПО
Т1.Наименование;
// 2. Используем шаги бинарной склейки.
// На каждом этапе мы уменьшаем количество строк вдвое, удваивая длину строки.
ВЫБРАТЬ
ВЫРАЗИТЬ((НомерСтроки - 1) / 2 КАК ЧИСЛО(15, 0)) КАК Группа,
МАКСИМУМ(ВЫБОР КОГДА НомерСтроки % 2 = 1 ТОГДА Значение ИНАЧЕ "" КОНЕЦ) +
МАКСИМУМ(ВЫБОР КОГДА НомерСтроки % 2 = 0 ТОГДА "; " + Значение ИНАЧЕ "" КОНЕЦ) КАК СклееннаяСтрока
ПОМЕСТИТЬ Шаг1
ИЗ
ПронумерованныеСтроки
СГРУППИРОВАТЬ ПО
ВЫРАЗИТЬ((НомерСтроки - 1) / 2 КАК ЧИСЛО(15, 0));
Важные нюансы реализации:
+) платформа 1С накладывает ограничение на результирующую строку. Обычно это 1024 символа (зависит от версии СУБД). Если сумма длин всех строк превысит этот лимит, произойдет обрезание данных.ВЫРАЗИТЬ(Поле КАК СТРОКА(200)), чтобы задать фиксированную длину.Проанализируем ситуацию в зависимости от контекста:
СоединитьСтроки(). Это стандарт платформы.Помните, что избыточная сложность запроса может привести к трудностям при его отладке. В большинстве случаев разделение логики на «получение данных в запросе» и «склейку в коде» является лучшей практикой разработки на платформе 1С.