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