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