При разработке аналитических отчетов в системе компоновки данных (СКД) часто возникает задача комбинированного расчета показателей. Например, требуется отобразить средний остаток товара по дням на уровне детальной аналитики (номенклатура, характеристика), а на уровнях вышестоящих группировок (организация, ответственный) и в общем итоге получить не общее среднее и не простую сумму всех строк, а сумму средних значений по позициям.
Разберем типичные сложности, возникающие при реализации такой логики, выясним причины некорректного подсчета общего итога и рассмотрим по шагам правильную настройку ресурсов и полей набора данных.
Рассмотрим структуру отчета со следующей иерархией группировок:
Если для ресурса КоличествоКонечныйОстаток задать стандартное агрегатное выражение Среднее(КоличествоКонечныйОстаток), то на уровне группировки Характеристика СКД рассчитает среднее значение по дням. Однако на уровнях Номенклатура, Организация и в общем итоге система также продолжит вычислять среднее значение по всем строкам выборки, вместо того чтобы сложить полученные средние остатки по характеристикам.
Если же попытаться использовать функцию работы с массивами вида:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Среднее(КоличествоКонечныйОстаток)", "ХарактеристикаНоменклатуры"))
то на промежуточных уровнях результат может сойтись, но в строке Общий итог данные будут рассчитаны некорректно. Проанализируем причину такого поведения.
Функция ВычислитьВыражениеСГруппировкойМассив(Выражение, Группировки) формирует массив значений по указанным полям группировки и затем передает его во внешнюю агрегатную функцию (в нашем случае Сумма).
Когда во втором параметре передается только одно поле "ХарактеристикаНоменклатуры", система строит массив без учета уникальности всей вышестоящей иерархической цепочки. Если одна и та же характеристика или номенклатура встречается в разных организациях или у разных ответственных, в контексте общего итога происходит неверное агрегирование и схлопывание данных.
Для корректного суммирования на верхних уровнях и в общем итоге необходимо явно передавать весь перечень вышестоящих группировок, однозначно определяющих контекст строки.
Разберем по шагам, как правильно настроить вкладку Ресурсы для получения корректных результатов на всех уровнях отчета.
КоличествоКонечныйОстаток.
Сумма(ВычислитьВыражениеСГруппировкойМассив("Среднее(КоличествоКонечныйОстаток)", "Ответственный, Организация, Номенклатура, ХарактеристикаНоменклатуры"))
ХарактеристикаНоменклатуры указать выражение: Среднее(КоличествоКонечныйОстаток)Номенклатура, Организация, Ответственный и общего итога указать выражение со сверткой массива по всей цепочке аналитики.Посмотрим на следующую ситуацию: пользователь отключает отображение группировки День в настройках отчета, после чего расчет средних остатков снова ломается.
Выясним причину: СКД автоматически оптимизирует SQL-запрос к базе данных. Если поле День не выводится в отчет, не используется в текущих группировках и отборах, платформа исключает его из секции ВЫБРАТЬ и СГРУППИРОВАТЬ ПО результирующего запроса. Данные схлопываются еще на уровне СУБД, и среднее по дням рассчитать становится невозможно.
Чтобы зафиксировать детализацию данных независимо от пользовательских настроек структуры отчета, выполним следующие действия:
День (или поле периода, по которому считается среднее).Установка признака Обязательное гарантирует, что поле периода всегда будет присутствовать в тексте исполняемого запроса и группировке на уровне СУБД, сохраняя необходимую плотность строк для вычисления среднего остатка.
Если отчет строится на больших объемах данных, постоянный расчет массива значений в памяти СКД может влиять на скорость формирования. Рассмотрим альтернативные архитектурные решения:
Организация + Номенклатура + Характеристика средствами языка запросов. В этом случае в СКД передается уже готовый средний показатель, а на вкладке ресурсов используется стандартная и быстрая функция Сумма(КоличествоКонечныйОстаток).ОстаткиИОбороты с периодичностью День и настроить дополнение периодов в СКД (свойство поля Тип дополнения: День).