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