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