При разработке отчетов на базе системы компоновки данных (СКД) часто возникает задача, когда в детальных записях выводятся стандартные показатели, а в строке общего итога требуется рассчитать данные не по всем строкам, а только по тем, которые удовлетворяют определенному условию (например, рассчитать общее среднее только для определенной категории или статуса). Разберем по шагам, как правильно настроить такие вычисления в СКД.
Выясним причину, почему стандартная конструкция условного выбора может давать неверный результат. Если мы напишем выражение вида:
Среднее(ВЫБОР КОГДА Статус = &НужныйСтатус ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ)
то СКД учтет ветку ИНАЧЕ 0 как полноценное числовое значение. В результате нули войдут в общее количество строк (знаменатель), и итоговое среднее значение окажется сильно заниженным.
Агрегатная функция Среднее() в СКД обладает важной особенностью: она автоматически игнорирует значения NULL, исключая их как из числителя (суммы), так и из знаменателя (количества записей).
Рассмотрим наиболее простое и эффективное решение задачи. Для вычисления среднего только по подходящим строкам в выражении ресурса необходимо возвращать NULL, если условие не выполняется.
Разберем по шагам настройку на вкладке Ресурсы:
ЕСТЬNULL(Среднее(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА ЧисловоеПоле ИНАЧЕ NULL КОНЕЦ), 0)
Функция ЕСТЬNULL защищает отчет от вывода пустого значения в случае, если в выборке не окажется ни одной строки, удовлетворяющей условию.
Проанализируем ситуацию, когда необходимо явно управлять числителем и знаменателем дроби или рассчитывать среднее по сложной формуле, где одно условие накладывается на сумму, а другое — на количество.
В этом случае агрегатные функции помещаются снаружи конструкции условного выбора:
ВЫБОР
КОГДА Количество(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА 1 ИНАЧЕ NULL КОНЕЦ) = 0
ТОГДА 0
ИНАЧЕ Сумма(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА ЧисловоеПоле ИНАЧЕ 0 КОНЕЦ)
/ Количество(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА 1 ИНАЧЕ NULL КОНЕЦ)
КОНЕЦ
Функция Количество() в СКД также не подсчитывает значения NULL, что позволяет точно определить число строк, вошедших в условие, и защититься от деления на ноль.
Посмотрим на пример, когда в детальных строках и обычных группировках показатель должен рассчитываться по стандартным правилам, а специальное условное выражение должно применяться только к общему итогу отчета.
Для этого в СКД предусмотрен механизм привязки выражений ресурсов к конкретным группировкам:
Сумма(СуммаДокумента)) и оставим колонку Рассчитывать по... пустой (выражение по умолчанию для всех уровней).ОбщийИтог.
ЕСТЬNULL(Среднее(ВЫБОР КОГДА ВидОперации = &НужныйВид ТОГДА СуммаДокумента ИНАЧЕ NULL КОНЕЦ), 0)
Такой подход позволяет сохранить обычные суммы в разрезе строк отчета, но переопределить логику в подвале таблицы.
Если условие фильтрации слишком сложное для языка выражений СКД или требует обращения к метаданным, можно вынести расчет в экспортную функцию общего модуля.
Для этого модуль должен быть неглобальным с признаком Сервер или Вызов сервера. В выражении ресурса СКД передадим данные через агрегатную функцию ТаблицаЗначений() или Массив():
МойОбщийМодуль.РассчитатьУсловныйИтог(ТаблицаЗначений(ПолеОтчета, ЧисловоеПоле))
В коде модуля выполняется обход переданной коллекции и возвращается итоговое числовое значение.