При разработке отчетов на схеме компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда добавление новой подчиненной группировки приводит к искажению (задвоению или умножению) итогов на верхних уровнях. Классический пример: отчет выводит приход товара по складам, номенклатуре и характеристикам, но нам потребовалось добавить внутрь характеристик еще одну группировку — например, ТипЦен или информацию из другого регистра. В результате количество прихода начинает суммироваться по каждому типу цен, и итоговые показатели по номенклатуре становятся неверными.
В этой статье мы подробно разберем, как решить эту проблему штатными средствами СКД без прибегания к выгрузке данных в таблицу значений и ее последующей ручной обработке. Мы рассмотрим несколько эффективных способов: от точечной настройки ресурсов до архитектурно правильного разделения запросов на несколько наборов данных.
Прежде чем перейти к решениям, проанализируем, почему так происходит. Когда мы соединяем в одном запросе таблицы с разной степенью детализации (например, остатки товаров и цены), СУБД возвращает декартово произведение строк. Если для одной характеристики товара существует три типа цен, то строка с количеством прихода этого товара продублируется трижды — по одной строке на каждый тип цен.
Если в настройках ресурсов СКД для поля КоличествоЕдПриход указано простое выражение Сумма(КоличествоЕдПриход), система послушно просуммирует все детальные записи, включая дубли. В итоге на уровне группировок Характеристика и Номенклатура мы получим утроенное значение.
---
Самый быстрый способ исправить итоги — настроить расчет одного и того же ресурса по-разному для каждого уровня группировки. В СКД мы можем добавлять одно и то же поле в список ресурсов несколько раз, указывая в колонке "Рассчитывать по..." конкретные группировки.
Рассмотрим по шагам, как настроить такую схему:
КоличествоЕдПриход для подчиненных уровней (где данные не должны суммироваться по типам цен).Пропишем выражения для каждого уровня:
Шаг A. Настройка для детальных записей и подчиненных группировок
Для группировок Характеристика и ТипЦен нам нужно брать не сумму, а максимальное или среднее значение, поскольку количество прихода для конкретной характеристики неизменно в разрезе цен. В поле "Выражение" пишем:
Максимум(КоличествоЕдПриход)
В колонке "Рассчитывать по..." указываем только: Характеристика, ТипЦен.
Шаг B. Настройка для вышестоящих группировок
Для группировок Номенклатура, Склад и для Общего итога нам нужно сложить максимальные значения, полученные на уровне характеристик. Для этого мы используем функцию ВычислитьВыражениеСГруппировкойМассив. В поле "Выражение" пишем:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(КоличествоЕдПриход)", "Номенклатура, Характеристика"))
В колонке "Рассчитывать по..." указываем: Номенклатура, Склад, ОбщиеИтоги (или оставляем это поле пустым, тогда формула применится ко всем остальным группировкам по умолчанию).
Важный нюанс: Обратите внимание на второй параметр функции ВычислитьВыражениеСГруппировкойМассив. Рекомендуется указывать связку полей через запятую — "Номенклатура, Характеристика". Если указать только "Характеристика", СКД выполнит группировку по характеристикам глобально во всем отчете. Если у разной номенклатуры совпадут наименования или коды характеристик, это приведет к некорректному расчету общих итогов.
---
Использование сложных агрегатных функций в ресурсах — рабочий инструмент, но при обработке больших массивов данных он может снижать производительность отчета. Более надежным и архитектурно правильным решением является разделение одного сложного запроса на два независимых набора данных в СКД.
Выясним, как это реализовать:
Склад, Номенклатура, Характеристика, КоличествоЕдПриход.Номенклатура и Характеристика.Почему этот подход решает проблему задвоения:
При такой архитектуре физического дублирования строк на уровне СУБД не происходит, так как таблицы не соединяются через ЛЕВОЕ СОЕДИНЕНИЕ непосредственно в запросе. СКД сама сопоставит строки при выводе отчета в дерево группировок. Расчет ресурсов (даже примитивной функцией Сумма(КоличествоЕдПриход)) будет производиться по первому набору данных, где записи по приходу уникальны. Итоги на всех уровнях свернутся абсолютно корректно и без сложных формул.
---
В некоторых сценариях нам может потребоваться исключить определенные записи подчиненной группировки прямо в процессе расчета агрегатных функций. Для этого можно использовать расширенный синтаксис функции СКД. Полный синтаксис выглядит следующим образом:
ВычислитьВыражениеСГруппировкойМассив(<Выражение>, <ВыраженияПолейГруппировки>, <ОтборЗаписей>, <ОтборГруппировок>)
Проанализируем параметры фильтрации:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(КоличествоЕдПриход)", "Характеристика", "ТипЦен <> &НежелательныйТипЦен"))
"Сумма(КоличествоЕдПриход) > 0"Использование отборов внутри расчетных функций дает разработчику гибкий инструмент управления итогами без изменения структуры исходного запроса.
---
Для исправления итогов при наличии дублирующих подчиненных группировок не нужно выгружать данные в таблицу значений. Вы можете использовать:
ВычислитьВыражениеСГруппировкойМассив, если нужно быстро поправить существующий отчёт.