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