Как рассчитать среднее значение от средних значений группировок в общем итоге СКД?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При построении сложных аналитических отчетов в схеме компоновки данных (СКД) нередко возникает нестандартная задача: на каждом уровне иерархии требуется рассчитать не прямое среднее по детальным записям, а среднее арифметическое от предварительно рассчитанных средних нижестоящих уровней. Рассмотрим типовую структуру группировок, разберем причины синтаксических ошибок при составлении таких формул и выясним, как правильно настроить ресурсы СКД для получения корректного общего итога.

Постановка задачи и анализ структуры данных

Представим трехуровневую иерархию отчета, где группировки подчинены друг другу в следующем порядке:

  1. РабочийЦентр — верхний уровень группировки строк;
  2. Номенклатура — вложенный уровень внутри рабочего центра;
  3. Регистратор (или детальные записи) — нижний уровень с первичными значениями поля ФактическаяПроизводительность.

На уровне номенклатуры рассчитывается среднее значение по детальным записям регистратора. На уровне рабочего центра необходимо получить среднее от рассчитанных показателей номенклатур. Наконец, в строке Общий итог требуется вывести среднее от значений, отображаемых в строках рабочих центров.

Посмотрим, какие формулы изначально настраиваются на вкладке Ресурсы для подчиненных уровней:

  1. Для группировки Номенклатура:
    
    Среднее(ВычислитьВыражениеСГруппировкойМассив("ФактическаяПроизводительность", "Регистратор"))
    
  2. Для группировки РабочийЦентр:
    
    Среднее(ВычислитьВыражениеСГруппировкойМассив("Среднее(ФактическаяПроизводительность)", "Номенклатура"))
    

Трудность возникает при переходе к строке Общий итог. Если указать стандартное выражение вида Среднее(ВычислитьВыражениеСГруппировкойМассив("Среднее(ФактическаяПроизводительность)", "РабочийЦентр")), система вернет некорректный результат. Причина заключается в том, что СКД рассчитает прямое среднее по детальным записям для каждого рабочего центра, проигнорировав вычисленные средние уровня номенклатуры.

Причина ошибки и корректный синтаксис для общего итога

Проанализируем ситуацию: чтобы получить среднее от рабочих центров, которые, в свою очередь, берут среднее от номенклатур, напрашивается вложение одной функции ВычислитьВыражениеСГруппировкойМассив внутрь другой. Однако при попытке прямой записи парсер языка выражений СКД выдает синтаксическую ошибку.

Выясним причину ошибки: первый параметр функции ВычислитьВыражениеСГруппировкойМассив передается как строка. Если внутри этой строки встречается еще один вызов со строковыми литералами, внутренние кавычки необходимо удваивать (экранировать). Если кавычки не экранированы, парсер прерывает разбор строки раньше времени и воспринимает имя группировки как некорректную конструкцию.

Разберем по шагам правильное составление формулы для общего итога. В строке ресурса, где поле Рассчитывать по... установлено в значение Общий итог, указываем следующее выражение:


Среднее(ВычислитьВыражениеСГруппировкойМассив("Среднее(ВычислитьВыражениеСГруппировкойМассив(""Среднее(ФактическаяПроизводительность)"", ""Номенклатура""))", "РабочийЦентр"))

Обратим внимание на синтаксис: вокруг выражения ""Среднее(ФактическаяПроизводительность)"" и имени группировки ""Номенклатура"" используются именно двойные кавычки. В таком виде СКД корректно скомпилирует выражение: сначала будет сформирован массив средних значений по номенклатурам для каждого рабочего центра, затем вычислено среднее для каждого рабочего центра, и на финальном шаге внешний вызов Среднее() свернет полученный массив в итоговую цифру отчета.

Ограничения и подводные камни вложенных агрегаций

Несмотря на то что данный способ решает задачу без изменения схемы данных, при его использовании важно учитывать технические ограничения платформы:

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

Альтернативные способы реализации

Рассмотрим более устойчивые и производительные варианты, которые позволяют избежать тяжелых строковых конструкций с экранированием.

1. Расчет через промежуточные вычисляемые поля

Чтобы упростить чтение формул и снизить риск синтаксической ошибки, промежуточный расчет по подчиненной группировке можно вынести на вкладку Вычисляемые поля. В поле задается выражение агрегации по номенклатуре, а на вкладке Ресурсы используется уже подготовленное имя поля, что избавляет от необходимости удваивать кавычки внутри одной строки.

2. Перенос расчетов на уровень запроса

Наиболее надежный подход при работе с большими базами данных — предварительная агрегация показателей во временных таблицах запроса:

  1. В первой временной таблице вычисляется среднее по детальным записям до уровня номенклатуры;
  2. Во второй таблице рассчитывается среднее от полученных строк до уровня рабочего центра;
  3. Итоговые коэффициенты соединяются с основной выборкой.

В этом случае СКД оперирует уже готовыми математическими величинами и формирует итоги стандартными средствами без сложных манипуляций с массивами в памяти.

3. Использование функций общего модуля

Если требуется применить сложный алгоритм усреднения (например, отсекать выбросы или фильтровать определенные строки), выражение в ресурсе можно делегировать серверной экспортной функции: ИмяМодуля.РассчитатьИтог(ВычислитьВыражениеСГруппировкойМассив(...)). В коде на встроенном языке 1С массив значений обрабатывается с максимальным контролем граничных условий.

4. Взвешенное среднее вместо среднего от средних

С точки зрения математической статистики простое среднее от средних величин корректно только тогда, когда объемы выборок на всех рабочих центрах строго одинаковы. Если объемы различаются, невзвешенный итог дает искажение. Если бизнес-логика позволяет перейти к классическому взвешенному среднему (отношение общего фактического объема к общему затраченному времени), формула ресурса упрощается до стандартного деления: Сумма(Объем) / Сумма(Время), что автоматически дает математически точный результат на любом уровне иерархии и в общих итогах.

← На главную