При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда стандартные агрегатные функции ведут себя не так, как ожидается. Типичный пример: на уровне детальных записей или вложенной группировки мы вычисляем некое значение (например, максимальный пробег по водителю), а на уровне вышестоящей группировки (например, автопарк или гараж) нам нужно получить не общую сумму всех записей из базы, а именно сумму этих максимумов. Рассмотрим подробнее, как решить эту задачу правильно.
Разберем ситуацию на примере. Допустим, у нас есть водитель, у которого в течение дня зафиксировано несколько поездок. Если мы выберем Максимум(Пробег), СКД покажет нам пиковое значение пробега для этого водителя. Однако, когда мы переходим к итогам по Гаражу, обычная функция Сумма(Пробег) сложит все физические строки из результата запроса, которые относятся к этому гаражу. Если по каждому водителю было по 10 записей, итоговая сумма будет в разы больше, чем сумма реальных пробегов водителей. Нам же нужно заставить систему сначала найти максимум по каждому водителю, а потом сложить эти промежуточные итоги.
Самый эффективный и современный способ решения этой проблемы в СКД — использование функции ВычислитьВыражениеСГруппировкойМассив. Эта функция позволяет собрать результаты расчетов по нижестоящей группировке в массив, который затем можно обработать другой агрегатной функцией.
Проанализируем синтаксис, который необходимо использовать на закладке Ресурсы для поля итогов:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(Пробег)", "ТСВодитель"))
Разберем этот расчет по шагам:
"Максимум(Пробег)" — это выражение, которое будет вычисляться для каждой уникальной записи в группировке, указанной вторым параметром. Обратите внимание, что выражение обязательно пишется в кавычках."ТСВодитель" — это имя группировки, по которой мы хотим собрать данные. Система «пробежится» по всем водителям внутри текущего гаража и для каждого вычислит его персональный максимум.ВычислитьВыражениеСГруппировкойМассив вернет нам набор (массив) этих самых максимумов.Сумма(...) сложит все элементы полученного массива, давая нам правильный итог на уровне Гаража.В СКД предусмотрен механизм, позволяющий задавать разные формулы расчета ресурса для разных уровней отчета. Это очень удобно, когда логика «схлопывания» данных на разных этапах отличается. Посмотрим, как настроить закладку Ресурсы:
Для одного и того же поля (например, Пробег) мы добавим две строки:
Выражение: Максимум(Пробег)
Рассчитывать по...: ТСВодитель
Выражение: Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(Пробег)", "ТСВодитель"))
Рассчитывать по...: Гараж, Организация, Общий итог
Такой подход гарантирует, что система не запутается в контексте вычислений и на каждом уровне применит нужную математическую модель.
Существует еще один способ получить сумму итогов, используя функцию ВычислитьВыражение с указанием области вычисления. Рассмотрим пример такой конструкции:
Сумма(ВычислитьВыражение("Максимум(Пробег)", "ТСВодитель", , "Первая", "Последняя"))
Выясним причину, почему этот метод используется реже. Он более ресурсозатратен для процессора сервера приложений 1С, так как требует более сложного анализа контекста группировок. Однако в специфических иерархических отчетах, где группировка может повторяться на разных уровнях, этот метод может оказаться более стабильным.
При реализации подобных расчетов важно помнить о следующих моментах:
ВычислитьВыражениеСГруппировкойМассив первое выражение должно быть строковым. Если вы напишете Сумма(ВычислитьВыражениеСГруппировкойМассив(Максимум(Пробег), ...)) без кавычек, система выдаст ошибку, так как попытается вычислить максимум еще до передачи его в функцию массива."ТСВодитель" должен в точности совпадать с именем группировки, заданным на закладке "Настройки" схемы компоновки данных. Если имя группировки не задано явно, СКД использует имя поля, но лучше всегда назначать имя группировке вручную для надежности.Максимум вернет NULL. Вложенные агрегаты СКД обычно корректно обрабатывают NULL, игнорируя их при суммировании, но иногда полезно добавить ЕстьNull(..., 0) внутри выражения.Представим, что мы создаем отчет по выработке сотрудников. У нас есть записи о каждом выполненном задании. Нам нужно вывести общую сумму «лучших результатов» каждого сотрудника за месяц по отделам.
Проанализируем ситуацию: в отделе 5 сотрудников. Каждый выполнял задачи, и у каждого есть свой рекорд (максимальный балл). Обычная сумма баллов по отделу нам не интересна — нам нужна сумма их рекордов.
Настраиваем ресурс РекордныйБалл:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(Балл)", "Сотрудник"))
Теперь на уровне группировки "Отдел" мы увидим именно то, что хотели: сложенные максимальные достижения каждого работника. Это решение делает отчеты гибкими и позволяет реализовывать сложную бизнес-логику без изменения самого текста запроса к базе данных.