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