В процессе создания отчетов в Системе компоновки данных (СКД) часто возникает задача расчета средних значений. На первый взгляд, это кажется простым, но при работе с предварительно сгруппированными данными можно столкнуться с неверными результатами. Разберем на конкретном примере, как корректно вычислить средний возраст, и рассмотрим два основных подхода к решению этой задачи.
Представим ситуацию: у нас есть запрос, который группирует сотрудников по возрасту, полу и должности, и для каждой такой группы считает их количество.
ВЫБРАТЬ
СУММА(1) КАК КоличестоСотрудников,
Должность,
Возраст,
Пол
ИЗ
Справочник.Сотрудники
СГРУППИРОВАТЬ ПО
Должность,
Возраст,
Пол
При выводе отчета мы видим строки вида: "Возраст 25, Количество 2". Интуитивная попытка рассчитать среднее как Возраст / КоличествоСотрудников (25 / 2 = 12.5) приведет к абсурдному результату. Очевидно, что средний возраст двух человек, которым по 25 лет, должен быть равен 25. Выясним, как получить правильный результат.
Этот метод подходит, если вы по каким-то причинам не можете или не хотите менять исходный запрос, который уже отдает сгруппированные данные. Суть метода заключается в вычислении взвешенного среднего, где "весом" для каждого возраста выступает количество сотрудников этого возраста.
Формула для расчета выглядит так:
Средний возраст = Общая сумма возрастов всех сотрудников / Общее количество сотрудников
В терминах полей СКД это преобразуется в следующее выражение для ресурса:
Сумма(Возраст * КоличестоСотрудников) / Сумма(КоличествоСотрудников)
Проанализируем эту формулу:
Возраст * КоличестоСотрудников — эта часть вычисляет суммарный возраст для каждой строки в наборе данных. Например, для строки "Возраст 25, Количество 2" результат будет 50.Сумма(Возраст * КоличестоСотрудников) — внешняя функция Сумма() складывает эти "суммарные возрасты" по всем строкам группировки, получая общую сумму возрастов всех сотрудников.Сумма(КоличествоСотрудников) — эта часть просто суммирует количество сотрудников по всем строкам, получая общее число людей.Разберем по шагам, как настроить такой расчет в СКД:
Сумма(Возраст * КоличестоСотрудников) / Сумма(КоличествоСотрудников).Этот способ абсолютно корректен, но он менее гибок, чем следующий.
Наиболее правильный и гибкий подход при работе с СКД — это предоставлять системе как можно более детальные, неагрегированные данные. Это позволяет использовать всю мощь встроенных механизмов вычислений и дает пользователю свободу в настройке группировок отчета.
В этом случае мы изменим исходный запрос так, чтобы он возвращал по одной записи на каждого сотрудника.
Шаг 1. Изменяем запрос набора данных
Убираем из запроса группировку и агрегатную функцию СУММА(). Вместо этого добавим поле с константой `1` для удобства подсчета количества.
ВЫБРАТЬ
1 КАК КоличествоСотрудников,
Должность,
Возраст,
Пол
ИЗ
Справочник.Сотрудники
Теперь на вход СКД поступает "сырой" список всех сотрудников с их характеристиками.
Шаг 2. Настраиваем ресурсы в СКД
Теперь настройка ресурсов становится тривиальной задачей. СКД сама выполнит все необходимые вычисления.
КоличествоСотрудниковСумма(КоличествоСотрудников)ВозрастСреднее(Возраст)Вот и все! Теперь СКД будет корректно рассчитывать и сумму сотрудников, и их средний возраст для любых уровней группировок, которые пользователь настроит в отчете (по полу, по должности, общий итог и т.д.).
Основная рекомендация при работе с СКД: избегайте предварительной агрегации данных в запросе, если это возможно. Передавайте в СКД детальные записи.
Преимущества такого подхода:
Сумма, Среднее, Минимум, Максимум, Количество) будут работать корректно.Предварительная агрегация в запросе оправдана в основном для оптимизации производительности при работе с очень большими объемами данных, когда передача всех детальных записей может существенно замедлить формирование отчета.