Почему не выводятся данные в макет после запроса в 1С и как это исправить

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

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

Причина 1. Несоответствие имен полей выборки и параметров ячеек макета

Проанализируем метод Параметры.Заполнить(). Этот метод сопоставляет имена параметров в области макета с именами свойств переданного объекта (выборки из результата запроса, структуры или строки таблицы значений). Заполнение происходит только при полном совпадении имен с учетом регистра или без него.

Посмотрим на пример ошибки. В запросе вычисляются поля с псевдонимами:


| СУММА(...) КАК ФАКТ,
| СУММА(...) КАК ВД,
| СУММА(...) КАК ВР,
| СУММА(...) КАК Сов,
| СУММА(...) КАК Пост

А в макете ячейки названы с разделением по категориям сотрудников: СпФ, СпП, СпС (для специалистов) и РФ, РП, РС (для руководителей). Команда ОснБлок.Параметры.Заполнить(Выборка) в данном случае заполнит только параметр Подразделение, так как имена числовых показателей просто не совпадают. Остальные колонки останутся пустыми.

Если параметры макета названы специфично, их необходимо присваивать явно либо переименовать поля в запросе:


// Явное присвоение параметров области из полей выборки
ОснБлок.Параметры.СпФ = Выборка.ФАКТ;
ОснБлок.Параметры.СпП = Выборка.Пост;
ОснБлок.Параметры.СпС = Выборка.Сов;

Причина 2. Ошибки при сравнении ссылочных типов (поиск по строке и неинициализированные переменные)

Часто в коде пытаются сопоставить категорию из строки выборки со строковым литералом или с не объявленной заранее переменной:


// Ошибка 1: переменная Специалисты не определена
Если строка.Категория = Специалисты Тогда 

// Ошибка 2: поле Категория хранит Ссылку, а сравнение идет со строкой
Если строка.Категория = "Специалисты" Тогда 

Поле Категория в регистрах сведений и кадровых документах типовых конфигураций (например, в 1С:ЗУП) практически всегда имеет тип ссылки на справочник (например, Справочники.КатегорииСотрудников). Сравнение ссылки со строкой всегда возвращает Ложь, из-за чего ветка заполнения параметров никогда не выполняется.

Также вызов метода тз.Найти("Специалисты", "Категория") возвращает либо строку таблицы значений, либо значение Неопределено. Проверка конструкции Если тз.Найти(...) = Истина Тогда принципиально неверна.

Разберем правильный подход: ссылки на нужные категории следует получить до начала цикла один раз, чтобы не перегружать базу лишними обращениями к данным:


// Получаем ссылки до входа в цикл обработки данных
КатегорияСпециалисты = Справочники.КатегорииСотрудников.НайтиПоНаименованию("Специалисты", Истина);
КатегорияРуководители = Справочники.КатегорииСотрудников.НайтиПоНаименованию("Руководители", Истина);
КатегорияРабочие = Справочники.КатегорииСотрудников.НайтиПоНаименованию("Вспомогательные рабочие", Истина);

Для Каждого СтрТЗ Из ТаблицаДанных Цикл
    Если СтрТЗ.Категория = КатегорияСпециалисты Тогда
        ОснБлок.Параметры.СпФ = СтрТЗ.Факт;
        ОснБлок.Параметры.СпП = СтрТЗ.Пост;
        ОснБлок.Параметры.СпС = СтрТЗ.Совм;
    ИначеЕсли СтрТЗ.Категория = КатегорияРуководители Тогда
        ОснБлок.Параметры.РФ = СтрТЗ.Факт;
        ОснБлок.Параметры.РП = СтрТЗ.Пост;
        ОснБлок.Параметры.РС = СтрТЗ.Совм;
    КонецЕсли;
КонецЦикла;

Причина 3. Неправильная точка вывода области макета в табличный документ

Выясним еще одну распространенную причину: вызов ТабличныйДокумент.Вывести(ОснБлок) внутри цикла по категориям. Если по одному подразделению в запросе возвращается три строки (руководители, специалисты, рабочие), то при таком подходе в печатный документ выводятся три отдельные строки на одно подразделение. При этом в первой строке заполнены только колонки руководителей (а остальные пустые), во второй — только специалистов, в третьей — только рабочих.

Кроме того, если область ОснБлок была получена один раз до цикла, неперезаписанные параметры сохраняют значения из предыдущей итерации, что приводит к некорректному дублированию цифр между строками.

Решение 1. Оптимальный вариант: перенос распределения категорий в сам запрос

Наиболее надежный и производительный путь — перенести логику разбивки по колонкам непосредственно в текст запроса с помощью конструкции ВЫБОР. В этом случае запрос вернет ровно одну строку на каждое подразделение, а имена колонок можно сделать полностью идентичными именам параметров макета.

Рассмотрим пример построения запроса и вывода данных:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	ТекущиеКадровые.ТекущееПодразделение КАК Подразделение,
|	// Колонки для специалистов
|	СУММА(ВЫБОР
|			КОГДА ДопРеквизиты.Категория = &КатегорияСпециалисты
|				И Состояния.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.Факт)
|			ТОГДА 1
|			ИНАЧЕ 0
|		КОНЕЦ) КАК СпФ,
|	СУММА(ВЫБОР
|			КОГДА ДопРеквизиты.Категория = &КатегорияСпециалисты
|				И ДопРеквизиты.ХарактерРаботы = ЗНАЧЕНИЕ(Перечисление.ХарактерРаботы.РаботающийНаПостояннойРаботе)
|			ТОГДА 1
|			ИНАЧЕ 0
|		КОНЕЦ) КАК СпП,
|	// Колонки для руководителей
|	СУММА(ВЫБОР
|			КОГДА ДопРеквизиты.Категория = &КатегорияРуководители
|				И Состояния.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.Факт)
|			ТОГДА 1
|			ИНАЧЕ 0
|		КОНЕЦ) КАК РФ,
|	СУММА(ВЫБОР
|			КОГДА ДопРеквизиты.Категория = &КатегорияРуководители
|				И ДопРеквизиты.ХарактерРаботы = ЗНАЧЕНИЕ(Перечисление.ХарактерРаботы.РаботающийНаПостояннойРаботе)
|			ТОГДА 1
|			ИНАЧЕ 0
|		КОНЕЦ) КАК РП
|ИЗ
|	РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровые
|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияСотрудников.СрезПоследних(&Период, ) КАК Состояния
|		ПО ТекущиеКадровые.Сотрудник = Состояния.Сотрудник
|	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеРеквизиты.СрезПоследних(&Период, ) КАК ДопРеквизиты
|		ПО ТекущиеКадровые.Сотрудник = ДопРеквизиты.Сотрудник
|ГДЕ
|	ТекущиеКадровые.ТекущееПодразделение В ИЕРАРХИИ(&ТекущееПодразделение)
|СГРУППИРОВАТЬ ПО
|	ТекущиеКадровые.ТекущееПодразделение
|УПОРЯДОЧИТЬ ПО
|	ТекущиеКадровые.ТекущееПодразделение.Наименование";

Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("ТекущееПодразделение", ВыбранноеПодразделение);
Запрос.УстановитьПараметр("КатегорияСпециалисты", Справочники.КатегорииСотрудников.НайтиПоКоду("000000001"));
Запрос.УстановитьПараметр("КатегорияРуководители", Справочники.КатегорииСотрудников.НайтиПоКоду("000000002"));

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

ТабДок.Очистить();
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ТабДок.Вывести(ОбластьШапка);

ОбластьСтрока = Макет.ПолучитьОбласть("ОснБлок");

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

ТабДок.Показать();

Решение 2. Сборка данных в одну строку через промежуточную таблицу или структуру

Если запрос изменить нельзя и он возвращает данные с группировкой по подразделениям и категориям построчно, то перед выводом строки в отчет необходимо объединить данные категорий для каждого подразделения. Разберем по шагам алгоритм на базе таблицы значений:

  1. Выгружаем результат запроса в таблицу значений: ТЗ = РезультатЗапроса.Выгрузить().
  2. Получаем список уникальных подразделений через копирование и сворачивание: ТЗПодразделений = ТЗ.Скопировать(); ТЗПодразделений.Свернуть("Подразделение");.
  3. В цикле по уникальным подразделениям отбираем строки с помощью ТЗ.НайтиСтроки(), заполняем область макета данными по всем категориям и только после этого выводим сформированную строку в ТабличныйДокумент.

Посмотрим на практическую реализацию этого метода:


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

// Получаем список уникальных подразделений
ТЗПодразделения = ТЗДанных.Скопировать();
ТЗПодразделения.Свернуть("Подразделение");

КатСпециалисты = Справочники.КатегорииСотрудников.НайтиПоКоду("000000001");
КатРуководители = Справочники.КатегорииСотрудников.НайтиПоКоду("000000002");

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

ТабДок.Показать();

Соблюдение этих правил гарантирует корректное сопоставление типов данных, исключает дублирование и обеспечивает правильный вывод числовых показателей в печатную форму отчета.

← На главную