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