Как в запросе 1С получить номер подчиненного документа через один уровень (цепочка подчиненности)?

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

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

Постановка задачи и анализ связей между объектами

Рассмотрим конкретный сценарий бизнес-логики, с которым часто сталкиваются разработчики:

  1. Первичным документом в системе является «Подтверждение заказа».
  2. На его основании создается промежуточный документ — «Инвойс от производителя». Однако связь между ними хранится не в шапке документа, а в строках табличной части Товары в реквизите Подтверждение (тип ссылки — ДокументСсылка.ПодтверждениеЗаказа). Такое решение часто применяется, когда один инвойс от производителя может закрывать позиции сразу нескольких разных подтверждений заказов.
  3. На основании документа «Инвойс от производителя» вводится финальный документ — «Инвойс». Здесь связь стандартная: в шапке «Инвойса» присутствует реквизит ДокументОснование, ссылающийся на «Инвойс от производителя».

Наша цель: в запросе по документу «Инвойс» получить номер самого первого исходного документа — «Подтверждение заказа».

Решение задачи с помощью двойного левого соединения (Двухуровневая связь)

Для решения этой задачи нам потребуется связать три таблицы. Поскольку связь между вторым и третьим документами находится в табличной части, мы должны соединять основную таблицу «Инвойса» не просто с шапкой «Инвойса от производителя», а напрямую с его табличной частью Товары. Проанализируем базовый вариант такого запроса:


ВЫБРАТЬ
    ПодтверждениеЗаказа.Номер КАК НомерПодтверждения
ИЗ
    Документ.Инвойс КАК Инвойс
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ИнвойсОтПроизводителя.Товары КАК ИнвойсОтПроизводителяТовары
        ПО ИнвойсОтПроизводителяТовары.Ссылка = Инвойс.ДокументОснование
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПодтверждениеЗаказа КАК ПодтверждениеЗаказа
        ПО ПодтверждениеЗаказа.Ссылка = ИнвойсОтПроизводителяТовары.Подтверждение
ГДЕ
    Инвойс.Ссылка = &Инвойс

Давайте подробно разберем, как работает этот запрос по шагам:

  1. Мы выбираем исходный документ Инвойс и накладываем на него фильтр по конкретной ссылке в параметре &Инвойс.
  2. Первое ЛЕВОЕ СОЕДИНЕНИЕ сопоставляет документ-основание из шапки «Инвойса» с полем Ссылка табличной части ИнвойсОтПроизводителя.Товары. В результате мы получаем доступ ко всем строкам промежуточного инвойса.
  3. Второе ЛЕВОЕ СОЕДИНЕНИЕ связывает полученную ссылку на подтверждение из реквизита табличной части (Подтверждение) с физической таблицей документа ПодтверждениеЗаказа, откуда мы и забираем нужный нам реквизит Номер.

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

Критические проблемы простого запроса и способы их решения

Проблема А. Дублирование строк (Размножение выборки)

Связывание таблиц идет через табличную часть Товары. Если в документе «Инвойс от производителя» содержится, например, 15 строк с товарами, то данный запрос вернет ровно 15 одинаковых записей с одним и тем же номером «Подтверждения заказа» (при условии, что все строки ссылались на одно подтверждение). Если этот запрос используется для вывода информации на форму или в печатную форму, данные будут продублированы.

Как исправить: В секцию ВЫБРАТЬ необходимо добавить ключевое слово РАЗЛИЧНЫЕ для свертки одинаковых строк.

Проблема Б. Множественность связей (Разные подтверждения в одном инвойсе)

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

Как исправить: Мы применим группировку СГРУППИРОВАТЬ ПО и агрегатную функцию МИНИМУМ к полю ссылки, а уже затем получим номер этого документа.

Проблема В. Производительность СУБД и индексация полей

Связывание таблиц по реквизитам табличных частей — крайне ресурсоемкая операция. По умолчанию реквизиты табличных частей в платформе 1С не индексируются. При работе с большими объемами данных СУБД будет вынуждена выполнять полное сканирование таблиц (Table Scan), что приведет к блокировкам и медленной работе системы.

Как исправить:

  1. В конфигураторе для реквизита Подтверждение в табличной части Товары документа ИнвойсОтПроизводителя обязательно установите свойство «Индексировать». Это позволит СУБД мгновенно находить нужные связи.
  2. Для построения сложных отчетов или при выборке пакета документов настоятельно рекомендуется сначала отобрать связи во временную таблицу, проиндексировать её и только затем соединять с физическими таблицами документов.

Оптимизированный и безопасный вариант запроса

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Инвойс.Ссылка КАК Инвойс,
    ИнвойсОтПроизводителяТовары.Подтверждение КАК ПодтверждениеЗаказа
ПОМЕСТИТЬ ВТ_СвязиДокументов
ИЗ
    Документ.Инвойс КАК Инвойс
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ИнвойсОтПроизводителя.Товары КАК ИнвойсОтПроизводителяТовары
        ПО ИнвойсОтПроизводителяТовары.Ссылка = Инвойс.ДокументОснование
ГДЕ
    Инвойс.Ссылка В (&МассивИнвойсов)
    И ИнвойсОтПроизводителяТовары.Подтверждение <> ЗНАЧЕНИЕ(Документ.ПодтверждениеЗаказа.ПустаяСсылка)

ИНДЕКСИРОВАТЬ ПО
    ПодтверждениеЗаказа
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_СвязиДокументов.Инвойс КАК Инвойс,
    ВТ_СвязиДокументов.ПодтверждениеЗаказа КАК ПодтверждениеЗаказа,
    ПодтверждениеЗаказа.Номер КАК НомерПодтверждения
ИЗ
    ВТ_СвязиДокументов КАК ВТ_СвязиДокументов
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПодтверждениеЗаказа КАК ПодтверждениеЗаказа
        ПО ПодтверждениеЗаказа.Ссылка = ВТ_СвязиДокументов.ПодтверждениеЗаказа

Этот подход гарантирует высокую скорость выполнения даже на базах данных объемом в терабайты, так как мы предварительно отсекаем пустые ссылки, исключаем дубликаты строк на уровне СУБД с помощью РАЗЛИЧНЫЕ и принудительно индексируем поле связи во временной таблице перед финальным левым соединением.

Альтернативные и более универсальные подходы

Помимо прямого написания запросов со сложными левыми соединениями, существуют другие системные механизмы платформы 1С и Библиотеки стандартных подсистем (БСП), о которых важно знать разработчику.

Использование критериев отбора

Для построения связанных цепочек документов в платформу встроен специальный объект конфигурации — Критерий отбора (например, стандартный критерий СвязанныеДокументы). Он автоматически собирает информацию обо всех ссылках на документ-основание во всех реквизитах и табличных частях других объектов.

Обратиться к критерию отбора в запросе можно следующим образом:


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

Важное ограничение: Использовать виртуальную таблицу критерия отбора можно только для получения связей по одному конкретному документу, переданному в параметр &ЗначениеКритерия. Передать список документов в этот параметр невозможно. Соответственно, данный способ не подходит для массовой выборки данных в отчетах или динамических списках.

Использование регистров связи документов БСП

Если вы ведете разработку в современной типовой конфигурации 1С (такой как 1С:ERP, 1С:Комплексная автоматизация или 1С:Управление торговлей), обратите внимание на подсистему «Связанные документы» БСП.

В таких конфигурациях при проведении или записи документов автоматически заполняется специализированный регистр сведений (например, РегистрСведений.СвязиДокументов). Он хранит плоскую структуру связей вида «Исходный документ — Подчиненный документ».

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


ВЫБРАТЬ
    СвязиДокументов.СтатьяСвязи,
    СвязиДокументов.ДокументОснование КАК ПодтверждениеЗаказа,
    СвязиДокументов.ДокументОснование.Номер КАК НомерПодтверждения
ИЗ
    РегистрСведений.СвязиДокументов КАК СвязиДокументов
ГДЕ
    СвязиДокументов.Документ = &Инвойс

Использование механизмов БСП позволяет стандартизировать код, сделать его более читаемым и гарантирует высокую производительность при обновлении и масштабировании информационной системы.

← На главную