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