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