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