При разработке отчетов в 1С часто возникает типовая задача: у одного родительского объекта (например, контрагента) есть несколько подчиненных записей в регистре или табличной части (например, назначенные ответственные менеджеры). При обычном соединении таблиц в запросе одна запись контрагента дублируется столько раз, сколько у него менеджеров. В результате вместо компактной таблицы получается избыточный список строк.
Разберем основные подходы, позволяющие вывести такие данные в компактном виде: свернуть несколько менеджеров в одну ячейку через запятую с помощью языка выражений СКД, развернуть их в горизонтальные колонки через кросс-таблицу или обработать программно.
Прежде чем переходить к настройке вывода данных, проанализируем исходный запрос и устраним потенциальные узкие места, влияющие на производительность и полноту выборки.
В исходном варианте отбор накладывается в секции ГДЕ после выполнения среза последних, а главной таблицей выступает регистр сведений. Это приводит к двум проблемам:
Посмотрим на исправленный и оптимизированный вариант запроса:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
МТТ.Менеджер КАК Менеджер
ИЗ
Справочник.Контрагенты КАК Контрагенты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МТТ_СведенияОРазмерахВознагражденияМенеджеров.СрезПоследних(, Контрагент = &Ссылка) КАК МТТ
ПО (МТТ.Контрагент = Контрагенты.Ссылка)
ГДЕ
Контрагенты.Ссылка = &Ссылка
Если отчет строится без жесткого отбора по одной ссылке, условие среза последних и секцию ГДЕ можно опустить или доверить управление параметрами самой Системе компоновки данных.
В языке запросов 1С отсутствуют встроенные агрегатные функции для конкатенации строк (аналоги GROUP_CONCAT или STRING_AGG в SQL). Однако Система компоновки данных предоставляет мощные встроенные функции агрегации коллекций.
Разберем по шагам, как вывести список менеджеров через запятую в одной ячейке:
Менеджер в список ресурсов.
СоединитьСтроки(Массив(Менеджер), ", ")
Если требуется исключить возможное дублирование одинаковых значений, можно использовать конструкцию с таблицей значений:
СоединитьСтроки(ТаблицаЗначений(Менеджер), ", ")
Контрагент, а в список выбранных полей выведем Контрагент и ресурс Менеджер.При таком подходе СКД автоматически свернет строки по контрагенту, соберет всех его менеджеров во временный массив и объединит их в одну строковую ячейку с указанным разделителем.
Если требуется отобразить каждого менеджера в отдельном столбце с отметкой или значением, наиболее простым и гибким решением является использование структуры Таблица в настройках отчета СКД.
Разберем по шагам порядок настройки структуры:
1 или булево Истина) и объявим его ресурсом с выражением Максимум(ЕстьМенеджер) или Количество(Менеджер).Контрагент (вертикаль).Менеджер (горизонталь).В результате сформируется матрица, где по вертикали будут перечислены контрагенты, по горизонтали динамически сформируются колонки со всеми менеджерами, а на пересечениях будут стоять отметки об их закреплении.
Если отчет формируется полностью программно через объектную модель или результат запроса выгружается в стороннюю печатную форму, объединение значений можно выполнить средствами встроенного языка с помощью функции СтрСоединить.
Посмотрим на пример обработки результата запроса:
// Создаем соответствие для группировки менеджеров по контрагентам
МенеджерыПоКонтрагентам = Новый Соответствие;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Если ЗначениеЗаполнено(Выборка.Менеджер) Тогда
СписокМенеджеров = МенеджерыПоКонтрагентам[Выборка.Контрагент];
Если СписокМенеджеров = Неопределено Тогда
СписокМенеджеров = Новый Массив;
МенеджерыПоКонтрагентам.Вставить(Выборка.Контрагент, СписокМенеджеров);
КонецЕсли;
// Добавляем представление менеджера, избегая повторов
ПредставлениеМенеджера = Строка(Выборка.Менеджер);
Если СписокМенеджеров.Найти(ПредставлениеМенеджера) = Неопределено Тогда
СписокМенеджеров.Добавить(ПредставлениеМенеджера);
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Получение склеенной строки для конкретного контрагента
МассивДляВывода = МенеджерыПоКонтрагентам[ТекущийКонтрагент];
СтрокаМенеджеров = ?(МассивДляВывода <> Неопределено, СтрСоединить(МассивДляВывода, ", "), "Не назначены");
Такой подход обеспечивает полный контроль над форматированием строк, удалением дублей и заполнением ячеек макета при ручной компоновке табличного документа.