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

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

При разработке сложных отчетов или обработок перепроведения данных часто возникает задача: получить все подчиненные документы для целого списка родительских объектов. Например, нам нужно найти все Реализации товаров и услуг, созданные на основании выбранных за период Заказов клиентов (по аналогии с тем, как реализовано создание чеков ККМ на основании заказа). Первое решение, которое приходит в голову программисту — воспользоваться виртуальной таблицей КритерийОтбора.СвязанныеДокументы. Однако здесь мы сталкиваемся с жестким ограничением платформы 1С.

В этой статье мы разберем, почему стандартный подход с передачей временной таблицы в параметры критерия отбора не работает, проанализируем внутренние механизмы платформы и рассмотрим три эффективных способа решения этой задачи.

Почему критерий отбора не принимает временную таблицу

Рассмотрим типичную ошибку. Программист пытается передать в запрос временную таблицу втСписокЗаказов в качестве параметра виртуальной таблицы критерия отбора:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    СвязанныеДокументы.Ссылка 
ИЗ
    КритерийОтбора.СвязанныеДокументы(&втСписокЗаказов) КАК СвязанныеДокументы

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

Выясним причину такого поведения. На уровне СУБД обращение к критерию отбора транслируется в огромный запрос с использованием оператора UNION ALL. Платформа собирает данные из всех таблиц, которые входят в состав критерия. Если в состав "Связанных документов" включено 30 видов документов, СУБД выполнит поиск по всем 30 таблицам. Архитектура этой виртуальной таблицы оптимизирована для быстрого получения "дерева подчиненности" одного конкретного объекта (для глубокого изучения структуры связей рекомендуем использовать автоматический анализ графа зависимостей ссылок — для этого подойдёт инструмент построения графа зависимостей объектов 1С), а не массовой обработки данных.

Решение 1: Прямой запрос к таблицам (самый эффективный способ)

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

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


// 1. Помещаем наши заказы во временную таблицу
ВЫБРАТЬ
    ЗаказКлиента.Ссылка КАК Ссылка
ПОМЕСТИТЬ втЗаказы
ИЗ
    Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
    ЗаказКлиента.Дата МЕЖДУ &ДатаНачала И &ДатаКонца;

// 2. Получаем связанные реализации через соединение
ВЫБРАТЬ
    Реализация.Ссылка КАК РеализацияСсылка,
    втЗаказы.Ссылка КАК ЗаказОснование
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ВНУТРЕННЕЕ СОЕДИНЕНИЕ втЗаказы КАК втЗаказы
    ПО Реализация.ДокументОснование = втЗаказы.Ссылка
ГДЕ
    НЕ Реализация.ПометкаУдаления;

Важный момент: если в вашей конфигурации (например, когда требуется создание счета на оплату на основании реализации в ERP или УТ 11.5) реализована многопунктовая связь, связь может храниться в табличной части. В этом случае соединение нужно делать не с шапкой документа, а с его табличной частью ДокументыОснования или аналогичной.

Решение 2: Динамическое формирование запроса по метаданным

Иногда мы не знаем заранее, какие именно документы могут быть связаны с исходными. В этом случае мы можем эмулировать работу критерия отбора, но для списка документов, что особенно актуально, если вы проектируете универсальный журнал или реестр документов с детальным просмотром. Мы можем программно прочитать состав критерия отбора и построить запрос динамически.

Рассмотрим пример кода, который формирует текст запроса на основе состава критерия СвязанныеДокументы:


ТекстЗапроса = "";
КритерийОбъект = Метаданные.КритерииОтбора.СвязанныеДокументы;

Для Каждого ЭлементСостава Из КритерийОбъект.Состав Цикл
    
    // Получаем имя таблицы (например, Документ.РеализацияТоваровУслуг)
    ПутьКДанным = ЭлементСостава.ПолноеИмя();
    ИмяПоляСвязи = ЭлементСостава.Имя; // Реквизит, по которому идет связь
    
    Если ЗначениеЗаполнено(ТекстЗапроса) Тогда
        ТекстЗапроса = ТекстЗапроса + " ОБЪЕДИНИТЬ ВСЕ ";
    КонецЕсли;
    
    ТекстЗапроса = ТекстЗапроса + 
    "ВЫБРАТЬ Ссылка ИЗ " + ПутьКДанным + 
    " ГДЕ " + ИмяПоляСвязи + " В (ВЫБРАТЬ Ссылка ИЗ втЗаказы)";
    
КонецЦикла;

Проанализируем ситуацию: этот метод позволяет нам обойти ограничение "одной ссылки" и при этом сохранить универсальность критерия отбора. Мы одним запросом получаем все возможные подчиненные объекты для всего списка заказов. Это значительно упрощает создание объектов на основании других объектов в пакетном режиме и гораздо эффективнее, чем выполнять запросы в цикле — для этого подойдёт настройка правил создания связанных документов на основании без программирования.

Решение 3: Использование БСП (Библиотека стандартных подсистем)

В современных конфигурациях 1С часто реализована подсистема "Структура подчиненности". Мы можем воспользоваться программным интерфейсом этой подсистемы, предварительно изучив справочник по методам БСП с примерами использования. Рассмотрим возможность использования общего модуля ОбщегоНазначения или специализированных функций БСП.

Хотя БСП часто работает через те же критерии отбора, функции типа ОбщегоНазначения.ЗначенияРеквизитовОбъектов или специализированные методы получения связей часто позволяют передавать массивы ссылок. Проверьте наличие функции СтруктураПодчиненности.ПолучитьПодчиненныеОбъекты(МассивСсылок) в вашей версии конфигурации.

Почему нельзя использовать "Запрос в цикле"

В процессе обсуждения часто возникает идея: "Раз критерий принимает одну ссылку, давайте просто пройдемся циклом по заказам и для каждого вызовем запрос". Посмотрим на это критически:

  1. Сетевые задержки: Каждый вызов запроса — это отдельное обращение к серверу СУБД. Если у вас 1000 заказов, вы сделаете 1000 лишних "раунд-трипов" по сети.
  2. Нагрузка на СУБД: Как мы выяснили, запрос критерия отбора содержит много UNION ALL. Выполнять сложный поиск по 20-30 таблицам 1000 раз подряд — это верный способ "положить" производительность системы.
  3. Транзакционные блокировки: При массовом выполнении таких запросов повышается риск возникновения таймаутов и ожиданий на блокировках.

Подведем итог: для решения задачи получения связанных документов для списка заказов, мы рекомендуем использовать Решение №1 (Прямой запрос), если состав документов известен, или Решение №2 (Динамический запрос), если требуется полная универсальность. Использование критерия отбора напрямую в запросе оправдано только в формах объектов, где работа идет с одной конкретной ссылкой.

← На главную