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