При разработке отчетов в системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда результат запроса выглядит как «лесенка» или разреженная таблица. Это происходит, когда данные объединяются из разных источников через оператор ОБЪЕДИНИТЬ (UNION). В итоге мы получаем несколько строк для одного и того же объекта, где в каждой строке заполнена только часть колонок, а остальные содержат NULL или пустые значения. Наша задача — «схлопнуть» эти строки в одну плотную строку, где будут заполнены все показатели.
Рассмотрим подробнее основные способы решения этой задачи, начиная от самых простых настроек компоновки и заканчивая программными методами обработки результата.
Проанализируем самый эффективный и простой метод, который не требует написания сложного кода. Мало кто знает, что стандартные агрегатные функции в СКД, такие как Максимум или Минимум, отлично работают не только с числами, но и со строками, датами и ссылочными типами данных.
Разберем этот механизм по шагам:
Максимум(ИмяПоля).Почему это работает? СКД при группировке игнорирует значения NULL. Если для одного ключа у вас есть три строки, где в первой заполнено «Поле1», во второй — «Поле2», а в третьей — «Поле3», то функция Максимум выберет единственное непустое значение для каждой колонки и объединит их в одну результирующую строку. Это классический способ превращения разреженного набора данных в плоский.
Иногда возникают ситуации, когда в одной колонке для одного ключа может быть несколько разных значений, и мы не хотим терять ни одно из них, выбирая только максимум. В этом случае нам поможет встроенная функция СКД СоединитьСтроки().
Посмотрим на пример выражения в ресурсах:
СоединитьСтроки(Различные НазваниеПоля, ", ")
Этот метод позволяет превратить вертикальный список значений в одну горизонтальную строку, перечисленную через запятую. Это исключает дублирование строк в отчете и делает таблицу компактной и читаемой.
Если нам нужно подтянуть значение из соседней строки (например, перенести данные из строки 2 в строку 1 на этапе компоновки), мы можем использовать функцию ВычислитьВыражение. Данная функция обладает мощным набором параметров, позволяющих имитировать работу аналитических функций SQL (таких как LEAD или LAG).
Выясним причину, по которой этот метод полезен: он позволяет обращаться к группировкам и записям без изменения самого текста запроса. Рассмотрим пример выражения:
ВычислитьВыражение("ИмяПоля", , , "Следующая", "Следующая")
Здесь четвертый и пятый параметры («Начало» и «Конец») указывают на то, что СКД должна взять значение из следующей записи относительно текущей. Это позволяет «подтягивать» данные в одну строку из разных уровней или последовательных записей набора данных.
Правильная настройка ролей полей на закладке Наборы данных также может повлиять на то, как СКД компонует результат. Проанализируем ситуацию, когда данные двоятся из-за связей между наборами данных.
Для решения проблемы «размножения» строк попробуем выполнить следующие действия:
Если преобразование таблицы подразумевает перенос значений из строк в заголовки колонок (так называемый Pivot), то лучшим решением будет использование элемента настроек Таблица. В СКД это делается очень просто:
СКД автоматически распределит данные по пересечениям, заполнив пропуски и объединив данные в плотную структуру.
Если стандартных механизмов СКД недостаточно для сложной трансформации, мы всегда можем прибегнуть к программной обработке. Рассмотрим алгоритм действий в модуле объекта отчета:
Перехватим процесс компоновки в процедуре ПриКомпоновкеРезультата. Вместо стандартного вывода в табличный документ, мы можем выгрузить результат во временную таблицу значений, программно «свернуть» её или обойти циклом для заполнения нужных полей, а затем передать модифицированную таблицу обратно в процессор вывода.
Пример программного обхода (схематично):
// Выгружаем результат в таблицу значений
ТаблицаРезультата = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультата);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Сворачиваем таблицу по ключевым полям, суммируя ресурсы
// или выбирая максимальные строковые значения в цикле
ТаблицаРезультата.Свернуть("КлючевоеПоле", "СуммовоеПоле");
// Далее выводим готовую ТЗ в отчет
Подводя итог, можно сказать, что в большинстве случаев проблема «разреженной таблицы» решается правильной настройкой Ресурсов с использованием функции Максимум. Это наиболее производительный и правильный путь с точки зрения идеологии системы компоновки данных.