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