Как правильно получить данные табличной части документа через запрос для печатной формы?

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

При разработке печатных форм в платформе 1С разработчики часто сталкиваются с ситуацией, когда данные из табличной части документа не выводятся в табличный документ или при выполнении запроса возникает ошибка вида {(2,30)}: Поле не найдено "Работы.МесячныйСписок". Разберем по шагам, почему возникают подобные проблемы и как правильно строить запросы к табличным частям.

Причины возникновения ошибок и пустого вывода

Проанализируем две основные причины, приводящие к некорректной работе алгоритма вывода печатной формы:

  1. Неправильный синтаксис при смене источника данных в запросе. Конструктор запросов при выборе реквизитов документа и его табличной части формирует синтаксис вложенных таблиц с круглыми скобками: Работы.МесячныйСписок.(Объект, Адрес) при источнике ИЗ Документ.Работы КАК Работы. Если после этого вручную или через конструктор изменить источник на саму таблицу части (Документ.Работы.МесячныйСписок), но оставить перечисление полей через скобки с именем вложенной таблицы, платформа выдаст ошибку, так как внутри самой таблицы части поля с таким именем больше нет.
  2. Особенности обхода выборки с вложенными таблицами. Метод Шапка.Параметры.Заполнить(Выборка) переносит только значения полей верхнего уровня. Если в запросе табличная часть выбрана как вложенная таблица, поле МесячныйСписок в выборке содержит вложенный объект типа ВыборкаИзРезультатаЗапроса, а не конкретные строковые или ссылочные значения. Без внутреннего цикла обхода строки на печать не попадут.
  3. Свойство ячеек в макете. Если код отрабатывает без ошибок, но ячейки остаются пустыми, выясним причину в свойствах ячеек табличного документа: для вывода значений реквизитов свойство Заполнение должно быть переключено в режим Параметр или Шаблон. Если оставлен режим Текст, метод заполнения параметров не окажет никакого эффекта.

Способ 1. Прямой запрос к табличной части документа

Рассмотрим самый простой и эффективный способ, когда для печати требуются только строки табличной части (или реквизиты шапки берутся через ссылку на документ). В этом случае в качестве таблицы источника в секции ИЗ указывается непосредственно табличная часть, а поля перечисляются обычным плоским списком.

Посмотрим на пример правильного текста запроса:


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

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

Обратите внимание на использование сортировки УПОРЯДОЧИТЬ ПО ТЧ.НомерСтроки. В реляционной базе данных порядок записей не гарантируется, поэтому для совпадения порядка строк на печати с исходным документом всегда следует явно указывать сортировку по номеру строки.

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


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

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

Способ 2. Использование вложенных выборок

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

Рассмотрим правильную структуру такого запроса:


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

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

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


ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьШапка     = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока    = Макет.ПолучитьОбласть("Строка");

ТабДок.Очистить();
ВставлятьРазделительСтраниц = Ложь;

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

Способ 3. Запрос с левым соединением и итогами

В типовых конфигурациях 1С наиболее стандартизированным подходом к формированию печатных форм является соединение таблицы шапки документа с таблицей его табличной части и группировка с помощью предложения ИТОГИ ПО. Это позволяет получить единый оптимизированный запрос без использования громоздких вложенных таблиц.

Посмотрим на пример такого построения:


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

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

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

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

При таком подходе вызов Выборка.Уровень() будет возвращать корректные значения (0 для уровня документа и 1 для детальных записей), что делает обход иерархических структур наглядным и удобным для чтения.

Рекомендации по работе с данными

Для предотвращения типичных ошибок придерживайтесь следующих правил:

  1. Не обращайтесь к табличной части через точку от ссылки. Вызов вида Ссылка.МесячныйСписок.Выгрузить() заставляет платформу считывать весь объект документа целиком в оперативную память. При формировании комплекта документов на печать это вызовет существенную нагрузку на серверную часть и базу данных. Использование запроса — всегда предпочтительный вариант.
  2. Разделяйте области макета. Не пытайтесь вывести строки табличной части в область, предназначенную для шапки. Создавайте как минимум две разные области: Шапка (для реквизитов документа) и Строка (для позиций табличной части).
  3. Контролируйте типы параметров. Конструкция ТЧ.Ссылка В(&Ссылка) одинаково корректно отрабатывает как при передаче массива или списка значений, так и одиночной ссылки. Однако если в параметр передан пустой массив, запрос вернет пустой результат без генерации системных ошибок.
← На главную