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