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

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

В практике разработчика 1С часто возникает задача: преобразовать вертикальный набор данных (строки таблицы) в одну горизонтальную строку с разделителями (например, через точку с запятой). В стандартном SQL для этого существуют функции типа GROUP_CONCAT или STRING_AGG, однако в языке запросов 1С подобные агрегатные функции для строк отсутствуют. Это связано с архитектурными ограничениями платформы, стремящейся к универсальности работы с различными СУБД (MS SQL, PostgreSQL, Oracle, IBM DB2).

В этой статье мы подробно проанализируем три основных подхода к решению этой задачи: от простого программного перебора до сложного «хакерского» метода реализации логики объединения прямо в тексте запроса.

Способ 1: Программный обход результата запроса

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

Проанализируем пример кода:


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

ТекстРезультат = "";
Разделитель = "; ";

Пока Выборка.Следующий() Цикл
    // Добавляем разделитель, если строка уже не пустая
    ТекстРезультат = ТекстРезультат + ?(ПустаяСтрока(ТекстРезультат), "", Разделитель) + Выборка.Наименование;
КонецЦикла;

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

Способ 2: Использование возможностей СКД (Системы компоновки данных)

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

В СКД на закладке "Вычисляемые поля" или в "Ресурсах" можно указать следующее выражение:

СоединитьСтроки(Выражение, Разделитель, Порядок)

Разберем параметры по шагам:

  1. Выражение: Поле, значения которого нужно объединить (например, Номенклатура.Наименование).
  2. Разделитель: Символ или строка, которая будет вставлена между значениями (например, "; ").
  3. Порядок: Выражение, определяющее очередность склейки (например, Дата Возникновения Возр).

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

Способ 3: Реализация агрегации внутри «чистого» запроса

Иногда возникает экстремальная потребность: получить склеенную строку в динамическом списке или внутри вложенного запроса, где нет доступа к коду 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. Ограничение длины: При операциях конкатенации в запросе (использование оператора +) платформа 1С накладывает ограничение на результирующую строку. Обычно это 1024 символа (зависит от версии СУБД). Если сумма длин всех строк превысит этот лимит, произойдет обрезание данных.
  2. Типизация: В запросе нельзя складывать строки неограниченной длины. Перед склейкой обязательно нужно использовать ВЫРАЗИТЬ(Поле КАК СТРОКА(200)), чтобы задать фиксированную длину.
  3. Производительность: Метод с бинарным деревом требует написания большого количества вложенных запросов (Шаг1, Шаг2, Шаг3 и т.д.). Для объединения 1024 строк понадобится 10 таких шагов (2 в 10-й степени).

Когда какой метод выбрать?

Проанализируем ситуацию в зависимости от контекста:

Помните, что избыточная сложность запроса может привести к трудностям при его отладке. В большинстве случаев разделение логики на «получение данных в запросе» и «склейку в коде» является лучшей практикой разработки на платформе 1С.

← На главную