При разработке отчетов и обработок в 1С часто возникает задача собрать данные из нескольких строк в одну. Типичный пример — когда к одному документу прикреплено несколько файлов, и в отчете нужно вывести их названия одной строкой через запятую, а не плодить дублирующиеся строки для одного и того же документа. Разберем детально, какими способами можно решить эту задачу, учитывая ограничения платформы 1С и возможности Системы компоновки данных (СКД).
Для начала проанализируем ситуацию с точки зрения обычного запроса. Важно понимать, что встроенный язык запросов 1С, который мы используем в объекте Запрос, на текущий момент не имеет встроенной агрегатной функции для склеивания строк. В секции СГРУППИРОВАТЬ ПО мы можем использовать СУММА, МАКСИМУМ или КОЛИЧЕСТВО, но попытка сложить строки приведет к ошибке. Поэтому, если задача должна быть решена именно «чистым» запросом без использования СКД, нам придется прибегнуть к программному перебору результата.
Если ваша задача — вывести данные в отчет, то использование СКД является самым правильным и простым путем. Платформа предоставляет специальную агрегатную функцию СоединитьСтроки(), которая предназначена именно для таких случаев. Рассмотрим подробнее ее синтаксис и настройки.
Функция имеет следующий формат: СоединитьСтроки(Выражение, Разделитель, ВыражениеУпорядочивания). Разберем параметры:
Наименование файла).", ", точка с запятой или даже перенос строки Символы.ПС.Рассмотрим алгоритм настройки в СКД:
ИмяФайла).
СоединитьСтроки(ИмяФайла, ", ", "ИмяФайла Возр")
Теперь при формировании отчета 1С автоматически сгруппирует все записи по остальным полям, а для имен файлов применит указанную функцию агрегации.
Если в вашей конфигурации используется БСП (что характерно для большинства современных решений, таких как ERP, УТ 11 или БП 3.0), файлы обычно хранятся в подчиненных справочниках. Выясним причину, почему это важно. Для каждого документа создается отдельный справочник вида [ИмяДокумента]ПрисоединенныеФайлы.
Для получения списка имен файлов нам нужно выполнить запрос к этому справочнику, установив связь по владельцу. Однако здесь есть важный нюанс: необходимо фильтровать помеченные на удаление файлы. Проанализируем пример запроса:
ВЫБРАТЬ
ПрисоединенныеФайлы.ВладелецФайла КАК СсылкаНаДокумент,
ПрисоединенныеФайлы.Наименование КАК ИмяФайла
ИЗ
Справочник.ЗаказПокупателяПрисоединенныеФайлы КАК ПрисоединенныеФайлы
ГДЕ
ПрисоединенныеФайлы.ПометкаУдаления = ЛОЖЬ
Получив этот набор данных в СКД, мы применяем упомянутую выше функцию СоединитьСтроки() в ресурсах, и задача решена.
Иногда возникают ситуации, когда разработка ведется с использованием прямых запросов к базе данных (через внешние источники или специфические интерфейсы). В этом случае функции будут зависеть от используемой СУБД. Посмотрим на примеры:
Microsoft SQL Server:
В современных версиях (2017+) доступна функция STRING_AGG. Пример использования:
SELECT DocumentID, STRING_AGG(FileName, ', ') AS AllFiles
FROM AttachmentTable
GROUP BY DocumentID;
Если же вы работаете на более старых версиях MS SQL, придется использовать конструкцию с FOR XML PATH, которая собирает строки в XML-формат, а затем преобразует их обратно в текст.
PostgreSQL:
Здесь используется функция string_agg(expression, delimiter). Она работает аналогично и очень эффективно справляется с объединением больших объемов строковых данных.
В новых версиях платформы 1С при работе с СКД можно использовать агрегатную функцию Массив(). Это дает еще больше гибкости. Выясним, как это работает:
Массив(НаименованиеФайла).СтрСоединить().Этот метод полезен, если вам нужно выполнить сложную программную обработку списка строк перед тем, как окончательно вывести их в отчет. Например, убрать дубли или применить специфическое форматирование к каждому элементу.
Если вы не используете СКД, а работаете в обычном модуле, единственный надежный способ — это пост-обработка выборки. Рассмотрим пример кода:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ..."; // Ваш запрос с выборкой файлов
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
ТекущийДокумент = Неопределено;
СписокФайлов = "";
Пока Выборка.Следующий() Цикл
Если ТекущийДокумент <> Выборка.Ссылка Тогда
// Здесь можно вывести накопленные данные предыдущего документа
ТекущийДокумент = Выборка.Ссылка;
СписокФайлов = Выборка.ИмяФайла;
Иначе
СписокФайлов = СписокФайлов + ", " + Выборка.ИмяФайла;
КонецЕсли;
КонецЦикла;
Подведем итог: для отчетов всегда выбирайте СКД и функцию СоединитьСтроки() — это наиболее быстрый и поддерживаемый метод, не требующий написания лишнего кода и учитывающий все особенности платформы.