Как рассчитать общий итог и среднее по условию в СКД?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов на базе системы компоновки данных (СКД) часто возникает задача, когда в детальных записях выводятся стандартные показатели, а в строке общего итога требуется рассчитать данные не по всем строкам, а только по тем, которые удовлетворяют определенному условию (например, рассчитать общее среднее только для определенной категории или статуса). Разберем по шагам, как правильно настроить такие вычисления в СКД.

Особенности работы агрегатных функций в СКД

Выясним причину, почему стандартная конструкция условного выбора может давать неверный результат. Если мы напишем выражение вида:

Среднее(ВЫБОР КОГДА Статус = &НужныйСтатус ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ)

то СКД учтет ветку ИНАЧЕ 0 как полноценное числовое значение. В результате нули войдут в общее количество строк (знаменатель), и итоговое среднее значение окажется сильно заниженным.

Агрегатная функция Среднее() в СКД обладает важной особенностью: она автоматически игнорирует значения NULL, исключая их как из числителя (суммы), так и из знаменателя (количества записей).

Способ 1. Использование функции Среднее() с возвратом NULL

Рассмотрим наиболее простое и эффективное решение задачи. Для вычисления среднего только по подходящим строкам в выражении ресурса необходимо возвращать NULL, если условие не выполняется.

Разберем по шагам настройку на вкладке Ресурсы:

  1. Перейдем на вкладку Ресурсы схемы компоновки данных.
  2. Добавим необходимое поле ресурса.
  3. В колонке Выражение укажем формулу:

ЕСТЬNULL(Среднее(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА ЧисловоеПоле ИНАЧЕ NULL КОНЕЦ), 0)

Функция ЕСТЬNULL защищает отчет от вывода пустого значения в случае, если в выборке не окажется ни одной строки, удовлетворяющей условию.

Способ 2. Явный расчет через Сумму и Количество

Проанализируем ситуацию, когда необходимо явно управлять числителем и знаменателем дроби или рассчитывать среднее по сложной формуле, где одно условие накладывается на сумму, а другое — на количество.

В этом случае агрегатные функции помещаются снаружи конструкции условного выбора:


ВЫБОР 
    КОГДА Количество(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА 1 ИНАЧЕ NULL КОНЕЦ) = 0 
        ТОГДА 0 
    ИНАЧЕ Сумма(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА ЧисловоеПоле ИНАЧЕ 0 КОНЕЦ) 
        / Количество(ВЫБОР КОГДА ПолеОтчета = &ЗначениеПоля ТОГДА 1 ИНАЧЕ NULL КОНЕЦ) 
КОНЕЦ

Функция Количество() в СКД также не подсчитывает значения NULL, что позволяет точно определить число строк, вошедших в условие, и защититься от деления на ноль.

Способ 3. Раздельный расчет для группировок и общего итога

Посмотрим на пример, когда в детальных строках и обычных группировках показатель должен рассчитываться по стандартным правилам, а специальное условное выражение должно применяться только к общему итогу отчета.

Для этого в СКД предусмотрен механизм привязки выражений ресурсов к конкретным группировкам:

  1. На вкладке Ресурсы добавим две строки для одного и того же поля.
  2. В первой строке оставим стандартное выражение (например, Сумма(СуммаДокумента)) и оставим колонку Рассчитывать по... пустой (выражение по умолчанию для всех уровней).
  3. Во второй строке в колонке Рассчитывать по... выберем предопределенное значение ОбщийИтог.
  4. В колонке Выражение для второй строки пропишем условный расчет:

ЕСТЬNULL(Среднее(ВЫБОР КОГДА ВидОперации = &НужныйВид ТОГДА СуммаДокумента ИНАЧЕ NULL КОНЕЦ), 0)

Такой подход позволяет сохранить обычные суммы в разрезе строк отчета, но переопределить логику в подвале таблицы.

Способ 4. Вызов функций общего модуля при сложных условиях

Если условие фильтрации слишком сложное для языка выражений СКД или требует обращения к метаданным, можно вынести расчет в экспортную функцию общего модуля.

Для этого модуль должен быть неглобальным с признаком Сервер или Вызов сервера. В выражении ресурса СКД передадим данные через агрегатную функцию ТаблицаЗначений() или Массив():

МойОбщийМодуль.РассчитатьУсловныйИтог(ТаблицаЗначений(ПолеОтчета, ЧисловоеПоле))

В коде модуля выполняется обход переданной коллекции и возвращается итоговое числовое значение.

← На главную