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