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