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