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