Как не выводить шапку таблицы в печатной форме 1С, если в выборке нет строк

Программист 1С v8.3 (Управляемые формы) Сфера услуг, туризм и социальный сектор
← На главную

При формировании сложных печатных документов часто возникает задача: документ содержит несколько логических секций (например, распределение студентов по категориям, список разных типов номенклатуры или услуг), и если по какому-то из условий строки отсутствуют, соответствующая шапка таблицы не должна выводиться в результирующий табличный документ. Рассмотрим причины возникновения этой проблемы и разберем несколько способов её решения.

Анализ типичных ошибок при выводе секций

Проанализируем исходную ситуацию. В типовом коде печатной формы вывод параметров шапки и самих областей шапки часто помещают до входа в цикл обработки строк:


Выборка1 = Запрос2.Выполнить().Выбрать(); 
ОбластьШапка1.Параметры.Заполнить(Выборка1);
ТабДок.Вывести(ОбластьШапка1);
ТабДок.Вывести(ОбластьСтудентыШапка1);

Выборка1.Следующий();
ВыборкаСтуденты2 = Выборка1.Студенты.Выбрать();
Пока ВыборкаСтуденты2.Следующий() Цикл
    ОбластьСтуденты.Параметры.Заполнить(ВыборкаСтуденты2);
    ТабДок.Вывести(ОбластьСтуденты);
КонецЦикла;

В приведенном фрагменте присутствуют сразу две критические ошибки:

  1. Обращение к выборке до вызова Следующий(): метод Выбрать() возвращает выборку, которая изначально установлена перед первой записью. Обращение к полям или вызов Заполнить(Выборка1) до первого вызова Следующий() заполнит параметры значениями Неопределено или вызовет исключение.
  2. Безусловный вывод областей: команды ТабДок.Вывести() выполняются до того, как система проверяет наличие строк во вложенной выборке. В результате, даже если студентов по заданному условию нет, пустой заголовок таблицы попадает в документ.

Разберем основные варианты правильной реализации вывода.

Вариант 1. Использование флага первой строки внутри цикла

Это самый простой и быстрый способ в реализации. Мы инициализируем булеву переменную-флаг перед началом обхода строк. Сами шапки выводятся только внутри цикла при обработке первой найденной записи, после чего флаг сбрасывается. Если выборка окажется пустой, цикл не выполнится ни разу, и шапка не попадет в отчет.

Посмотрим на пример реализации:


Выборка1 = Запрос2.Выполнить().Выбрать();

Если Выборка1.Следующий() Тогда
    
    // Заполняем реквизиты шапки документа
    ОбластьШапка1.Параметры.Заполнить(Выборка1);
    ОбластьШапка1.Параметры.Дата_Начала_Практики = Формат(Выборка1.Дата_начала_практики, "ДЛФ=D");
    ОбластьШапка1.Параметры.Дата_Конца_Практики = Формат(Выборка1.Дата_конца_практики, "ДЛФ=D");
    
    ВыборкаСтуденты = Выборка1.Студенты.Выбрать();
    
    НужноВывестиШапку = Истина;
    
    Пока ВыборкаСтуденты.Следующий() Цикл
        
        // Выводим шапку только перед первой строкой таблицы
        Если НужноВывестиШапку Тогда
            ТабДок.Вывести(ОбластьШапка1);
            ТабДок.Вывести(ОбластьСтудентыШапка1);
            НужноВывестиШапку = Ложь;
        КонецЕсли;
        
        // Выводим строку с данными
        ОбластьСтуденты.Параметры.Заполнить(ВыборкаСтуденты);
        ТабДок.Вывести(ОбластьСтуденты);
        
    КонецЦикла;
    
КонецЕсли;

Вариант 2. Проверка выборки на наличие данных перед выводом

Выясним, как избежать использования флагов. Для этого проверим наличие строк до вывода макета. В платформе 1С вложенная таблица Выборка1.Студенты возвращает объект РезультатЗапроса, у которого доступны методы Пустой() и Количество(), либо можно выполнить проверку по количеству записей выборки.

Разберем по шагам данный подход:


Выборка1 = Запрос2.Выполнить().Выбрать();

Если Выборка1.Следующий() Тогда
    
    // Проверяем, есть ли строки во вложенной табличной части
    Если НЕ Выборка1.Студенты.Пустой() Тогда
        
        ОбластьШапка1.Параметры.Заполнить(Выборка1);
        ТабДок.Вывести(ОбластьШапка1);
        ТабДок.Вывести(ОбластьСтудентыШапка1);
        
        ВыборкаСтуденты = Выборка1.Студенты.Выбрать();
        Пока ВыборкаСтуденты.Следующий() Цикл
            ОбластьСтуденты.Параметры.Заполнить(ВыборкаСтуденты);
            ТабДок.Вывести(ОбластьСтуденты);
        КонецЦикла;
        
    КонецЕсли;
    
КонецЕсли;

Вариант 3. Оптимизация запроса через обращение к табличной части и группировку

Рассмотрим важную особенность языка запросов 1С: когда запрос строится к шапке документа с выборкой вложенной таблицы Документ.Студенты.(...), наложение условия в секции ГДЕ по реквизитам вложенной таблицы фильтрует только сам документ, но во вложенную выборку попадают все строки документа, а не только удовлетворяющие условию.

Кроме того, выполнение нескольких отдельных запросов к одному документу неэффективно с точки зрения производительности. Правильнее построить один запрос напрямую к табличной части с использованием секции ИТОГИ.

Посмотрим на пример запроса и обхода:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	Студенты.Ссылка КАК Документ,
|	Студенты.Ссылка.Номер КАК Номер,
|	Студенты.Ссылка.Дата КАК Дата,
|	Студенты.Основа_обучения КАК Основа_обучения,
|	Студенты.База КАК База,
|	Студенты.ФИО_студента КАК ФИО_студента,
|	Студенты.Место_прохождения_практики КАК Место_прохождения_практики
|ИЗ
|	Документ.Выхода_на_практику.Студенты КАК Студенты
|ГДЕ
|	Студенты.Ссылка = &Ссылка
|ИТОГИ ПО
|	Основа_обучения,
|	База";

Запрос.УстановитьПараметр("Ссылка", Ссылка);

РезультатЗапроса = Запрос.Выполнить();

// Обходим группы: в результат попадут только существующие комбинации условий
ВыборкаГруппа = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаГруппа.Следующий() Цикл
    
    // Выводим шапку секции под конкретную категорию (Бюджет/Платник, 9/11 классов)
    ОбластьСтудентыШапка.Параметры.Заполнить(ВыборкаГруппа);
    ТабДок.Вывести(ОбластьСтудентыШапка);
    
    // Обходим детальные записи внутри группы
    ВыборкаДетали = ВыборкаГруппа.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        ОбластьСтуденты.Параметры.Заполнить(ВыборкаДетали);
        ТабДок.Вывести(ОбластьСтуденты);
    КонецЦикла;
    
КонецЦикла;

При таком подходе пустые секции отсекаются платформой автоматически на уровне группировок запроса, исключаются лишние обращения к СУБД, а код модуля печати становится компактным и легко поддерживаемым.

← На главную