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