Как в СКД вывести несколько значений в одну ячейку?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с задачей: для одного документа, контрагента или номенклатуры необходимо отобразить список подчиненных элементов (например, наименования прикрепленных файлов, контактные данные, сертификаты или серийные номера) в одной строке через запятую или другой разделитель. Если попытаться решить эту задачу простым соединением таблиц в запросе, на каждый подчиненный элемент создается отдельная строка, что приводит к размножению записей базового документа.

Рассмотрим подробно причины такого поведения, а также разберем все практические способы объединения нескольких значений в одну ячейку средствами СКД и встроенного языка 1С:Предприятия.

Почему задачу нельзя решить только запросом?

Проанализируем работу языка запросов 1С. В классическом SQL для подобных задач используются агрегатные функции вроде STRING_AGG или GROUP_CONCAT. Однако в языке запросов 1С агрегатные функции для конкатенации строк отсутствуют: оператор СУММА работает исключительно с числовыми типами данных, а функции КОЛИЧЕСТВО и КОЛИЧЕСТВО(РАЗЛИЧНЫЕ) возвращают только число. Склеить строковые данные на уровне одного запроса без фиксированного количества соединений невозможно, поэтому агрегация должна выполняться на уровне механизмов СКД или при предварительной подготовке данных.

Способ 1. Использование механизма ресурсов и функции СоединитьСтроки

Это штатный и наиболее производительный способ в СКД. Для того чтобы поле со списком файлов выводилось в одну ячейку, его необходимо сделать ресурсом, но с жестким ограничением расчета по группировкам, чтобы не формировались ненужные общие итоги.

Разберем по шагам настройку схемы компоновки данных:

  1. В наборе данных формируем запрос, выбирающий документ и наименование подчиненного объекта (например, файла):
    
    ВЫБРАТЬ
        ПрисоединенныеФайлы.ВладелецФайла КАК Документ,
        ПрисоединенныеФайлы.Наименование КАК ИмяФайла
    ИЗ
        Справочник.ДокументПрисоединенныеФайлы КАК ПрисоединенныеФайлы
    
  2. Перейдем на вкладку Ресурсы.
  3. Добавим поле ИмяФайла в список ресурсов. В колонке Выражение укажем агрегатную функцию СКД: СоединитьСтроки(СгруппироватьВМассив(Различные ИмяФайла), ", ") Использование конструкции Различные внутри СгруппироватьВМассив позволяет исключить дублирующиеся названия файлов, если они прикреплены повторно.
  4. В колонке Рассчитывать по... явно выберем поле группировки Документ. Если оставить это поле пустым, ресурс попытается рассчитаться для общего итога, что не всегда имеет смысл для строковых данных.
  5. На вкладке Настройки в структуре отчета создаем группировку по полю Документ (без детальных записей), а в выбранные поля добавляем Документ и наш ресурс ИмяФайла.

Способ 2. Использование связей наборов данных

Если в основном запросе выбирается множество реквизитов документа (автор, дата, сумма, организация), простое левое соединение с таблицей файлов может неоправданно увеличить объем промежуточной выборки. В таких сценариях эффективнее использовать два независимых набора данных и связать их на уровне СКД.

Рассмотрим пошаговую настройку архитектуры с двумя наборами:

  1. НаборДанных1 (Документы): запрос выбирает уникальные документы и их реквизиты:
    
    ВЫБРАТЬ
        Реализация.Ссылка КАК Документ,
        Реализация.Автор КАК Автор,
        Реализация.СуммаДокумента КАК Сумма
    ИЗ
        Документ.РеализацияТоваровУслуг КАК Реализация
    
  2. НаборДанных2 (Файлы): запрос выбирает список файлов по параметру документа:
    
    ВЫБРАТЬ
        Файлы.ВладелецФайла КАК Документ,
        Файлы.Наименование КАК ИмяФайла
    ИЗ
        Справочник.РеализацияТоваровУслугПрисоединенныеФайлы КАК Файлы
    ГДЕ
        Файлы.ВладелецФайла В(&Документ)
    
  3. Перейдем на вкладку Связи наборов данных и создадим строку связи:
    — Источник связи: НаборДанных1
    — Приемник связи: НаборДанных2
    — Условие связи: Документ
    — Параметры: Документ = Документ
  4. На вкладке Ресурсы для поля ИмяФайла прописываем выражение: СоединитьСтроки(ИмяФайла, ", ")

При таком подходе СКД сама передает массив документов в подчиненный запрос, выполняет группировку и склеивает строки только для тех документов, которые выводятся в результат.

Способ 3. Программная подготовка данных через процедуру ПриКомпоновкеРезультата

В случаях, когда алгоритм объединения строк требует сложной бизнес-логики, сортировки по нестандартным правилам или обращения к веб-сервисам, строку можно сформировать в модуле отчета до вывода макета.

Посмотрим на пример реализации в процедуре ПриКомпоновкеРезультата модуля отчета:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Получаем исходные данные запросом
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Файлы.ВладелецФайла КАК Документ,
        |   Файлы.Наименование КАК ИмяФайла
        |ИЗ
        |   Справочник.РеализацияТоваровУслугПрисоединенныеФайлы КАК Файлы
        |ИТОГИ ПО
        |   Документ";
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Формируем таблицу с уже объединенными строками
    ТаблицаФайлов = Новый ТаблицаЗначений;
    ТаблицаФайлов.Колонки.Добавить("Документ", Новый ОписаниеТипов("ДокументСсылка.РеализацияТоваровУслуг"));
    ТаблицаФайлов.Колонки.Добавить("СписокФайлов", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(0)));
    
    ВыборкаДокумент = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    Пока ВыборкаДокумент.Следующий() Цикл
        МассивИмен = Новый Массив;
        ВыборкаДетали = ВыборкаДокумент.Выбрать();
        Пока ВыборкаДетали.Следующий() Цикл
            МассивИмен.Добавить(СокрЛП(ВыборкаДетали.ИмяФайла));
        КонецЦикла;
        
        НоваяСтрока = ТаблицаФайлов.Добавить();
        НоваяСтрока.Документ = ВыборкаДокумент.Документ;
        НоваяСтрока.СписокФайлов = СтрСоединить(МассивИмен, "; ");
    КонецЦикла;
    
    // Передаем таблицу значений в схему компоновки
    ВнешниеНаборыДанных = Новый Структура("ТаблицаФайлов", ТаблицаФайлов);
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки, Истина);
    
КонецПроцедуры

Ошибки при добавлении многоуровневых группировок (Автор → Документ)

Выясним причину частой проблемы: когда отчет строится с иерархией (например, сначала группировка Автор, а внутри нее группировка Документ), строки документов могут начать двоиться или поле с файлами оказывается пустым.

Это происходит по двум причинам:

  1. В структуре отчета присутствуют детальные записи: если вложенная группировка настроена как Детальные записи, СКД выводит каждую запись физической выборки. Чтобы объединение сработало, группировка обязательно должна быть по полю Документ, а не детальными записями.
  2. Ограничение расчета ресурсов: если в ресурсе для колонки Рассчитывать по... выбрано только поле Документ, то на уровне группировки Автор поле со списком файлов будет пустым (что правильно, если автору не нужно склеивать файлы всех его документов вместе). Если же требуется выводить список всех файлов автора на верхнем уровне, в списке Рассчитывать по... необходимо добавить и поле Автор, либо очистить это свойство.
← На главную