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