При разработке отчетов в системе компоновки данных (СКД) часто возникает задача сравнения текущего значения в строке с общим итогом по всему отчету или по конкретной группе. Например, нам нужно посчитать, насколько время упаковки конкретного заказа отклоняется от общего времени упаковки всех заказов. На первый взгляд задача кажется простой, но сложность заключается в том, что система компоновки данных рассчитывает итоги уже после того, как сформированы детальные записи. Давайте разберем, как обойти это ограничение и реализовать расчет отклонения эффективно.
Для начала проанализируем, почему обычное вычитание в запросе или в поле выражения не сработает «в лоб». Система компоновки данных работает итеративно. Сначала она выбирает детальные записи, а затем, основываясь на настройках группировок, рассчитывает агрегатные функции (сумму, среднее, максимум). Когда СКД выводит детальную запись, она еще «не знает», каким будет общий итог по отчету. Однако в языке выражений СКД существуют специальные функции, которые заставляют систему выполнить дополнительный проход по данным или обратиться к уже рассчитанным результатам в других контекстах. Одной из таких ключевых функций является ВычислитьВыражение.
Рассмотрим основной и наиболее правильный метод решения задачи. Функция ВычислитьВыражение позволяет вычислить агрегатное значение в определенном контексте. Для нашей задачи нам нужно получить сумму по полю ВремяВСекундах в контексте всего отчета.
Синтаксис функции выглядит следующим образом:
ВычислитьВыражение(Выражение, Группировка, ТипРасчета)
Чтобы получить значение общего итога в каждой строке детальной записи, мы будем использовать следующую формулу:
ВычислитьВыражение("Сумма(ВремяВСекундах)", , "ОбщийИтог")
Разберем параметры подробнее:
Сумма от нашего поля. Это то значение, которое мы обычно видим в подвале отчета в колонке «Итого»."ОбщийИтог". Это критически важный параметр. Он сообщает СКД, что выражение должно быть рассчитано не по текущей строке или текущей группе, а по всем записям, входящим в отчет.Теперь, чтобы найти отклонение, мы просто вычитаем это выражение из значения текущей строки. Итоговая формула для вычисляемого поля будет выглядеть так:
ВремяВСекундах - ВычислитьВыражение("Сумма(ВремяВСекундах)", , "ОбщийИтог")
Теперь выясним, куда именно нужно вписать эти выражения, чтобы отчет заработал корректно. У нас есть два пути, и мы рассмотрим каждый из них.
Этот способ удобен, если вы хотите создать новое поле, которое будет доступно пользователю для выбора в настройках отчета.
ОтклонениеОтИтога.Сумма(ОтклонениеОтИтога) или оставить его пустым, если в итогах расчет отклонения не имеет смысла.Этот метод более гибкий, так как позволяет точно указать, на каком уровне группировок производить расчет.
ВремяВСекундах доступно.ВремяВСекундах в список ресурсов (если оно еще не там).Отклонение).ВычислитьВыражение.Детальные записи. Это гарантирует, что в строках с итогами по группам не будет выводиться бессмысленная информация, если это не требуется по задаче.Проанализируем ситуацию, когда в исходных данных могут быть пропуски. Если поле ВремяВСекундах содержит значение NULL, то любая математическая операция с ним вернет NULL. В результате колонка «Отклонение» окажется пустой. Чтобы этого избежать, всегда используйте защитную функцию ЕСТЬNULL.
Модернизированная формула будет выглядеть так:
ЕСТЬNULL(ВремяВСекундах, 0) - ВычислитьВыражение("Сумма(ЕСТЬNULL(ВремяВСекундах, 0))", , "ОбщийИтог")
Иногда задача стоит сложнее: нужно вычесть не общий итог по всему отчету, а итог по вышестоящей группе (например, отклонение времени упаковки товара от среднего времени по данной категории товаров). В этом случае нам поможет функция ВычислитьВыражениеСГруппировкойМассив.
Рассмотрим пример, где нужно получить сумму по родительской группировке:
Сумма(ВремяВСекундах) - ВычислитьВыражение("Сумма(ВремяВСекундах)", "ИмяВашейРодительскойГруппировки")
Здесь во втором параметре указывается имя группировки, заданное в настройках СКД. Это позволяет делать отчеты более информативными и многоуровневыми.
В обсуждениях на форумах иногда упоминается работа с «адресами ячеек». Этот метод подразумевает создание собственного Макета для отчета. Мы можем создать макет области итогов и макет детальных записей, присвоить им имена параметров и затем программно или через выражения макета вычислять разницу. Однако, это путь максимального сопротивления. Использование встроенных функций языка выражений СКД (таких как ВычислитьВыражение) считается «лучшей практикой» (best practice), так как такой отчет гораздо проще поддерживать, и он сохраняет гибкость при изменении настроек пользователем.
Посмотрим на финальные штрихи оформления отчета:
Отклонение < 0, то цвет текста — Красный."ОбщийИтог" фактически делает дополнительный проход по данным. На очень больших объемах данных (миллионы строк) это может незначительно повлиять на производительность, но для большинства стандартных отчетов это влияние неощутимо.Таким образом, мы выяснили, что использование функции ВычислитьВыражение является наиболее эффективным и универсальным способом для работы с итогами внутри детальных записей. Это открывает широкие возможности для создания аналитических отчетов со сложными расчетными показателями прямо в рамках стандартного механизма 1С.