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