Как в запросе 1С выбрать данные из табличной части через реквизит составного типа?

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

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

Способ 1. Использование оператора ОБЪЕДИНИТЬ ВСЕ

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

Проанализируем пример, где у нас есть два возможных типа документа-основания: Док1 и Док2. Нам нужно выбрать данные из их табличных частей Состав:


ВЫБРАТЬ
    ТЧ.Номенклатура КАК Номенклатура,
    ТЧ.Количество КАК Количество,
    ТЧ.Ссылка КАК ДокументОснование
ИЗ
    Документ.Док1.Состав КАК ТЧ
ГДЕ
    ТЧ.Ссылка = &ОснованиеДокумент

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ТЧ.Номенклатура,
    ТЧ.Количество,
    ТЧ.Ссылка
ИЗ
    Документ.Док2.Состав КАК ТЧ
ГДЕ
    ТЧ.Ссылка = &ОснованиеДокумент

В данном случае система обращается к конкретным физическим таблицам Документ.Док1.Состав и Документ.Док2.Состав. Если в параметре &ОснованиеДокумент передана ссылка на Док1, то второй запрос просто вернет пустой результат, а первый — нужные данные. Это надежный способ, который корректно отрабатывает на уровне SQL.

Способ 2. Использование оператора ССЫЛКА и вложенных запросов

Если нам нужно выбрать данные из табличных частей всех документов определенного типа, которые фигурируют в качестве оснований в другом списке документов, мы можем использовать оператор ССЫЛКА. Посмотрим на пример, когда мы выбираем данные для всех документов типа ОсновнойДокумент, у которых основанием является РеализацияТоваровУслуг:


ВЫБРАТЬ
    ТЧ.Номенклатура,
    ТЧ.Сумма
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
ГДЕ
    ТЧ.Ссылка В (
        ВЫБРАТЬ
            Док.ОснованиеДокумент
        ИЗ
            Документ.ОсновнойДокумент КАК Док
        ГДЕ
            Док.ОснованиеДокумент ССЫЛКА Документ.РеализацияТоваровУслуг
    )

Здесь крайне важно использование ключевого слова ССЫЛКА. Оно позволяет системе на уровне обращения к базе данных быстро отфильтровать только нужные типы записей, не прибегая к тяжелым соединениям со всеми возможными таблицами, входящими в составной тип.

Способ 3. Оптимизация через временные таблицы

При работе с большими объемами данных использование составных типов «в лоб» может привести к деградации производительности. Выясним причину: когда вы обращаетесь к реквизиту составного типа, SQL-сервер вынужден выполнять LEFT JOIN ко всем таблицам, которые входят в этот тип. Если их 20, запрос станет огромным. Чтобы этого избежать, проанализируем ситуацию и применим временные таблицы.

Рассмотрим правильный алгоритм:

  1. Сначала выберем все уникальные ссылки оснований во временную таблицу.
  2. Затем из этой временной таблицы выберем только те ссылки, которые относятся к первому типу (используя ГДЕ Ссылка ССЫЛКА Документ.Тип1).
  3. Аналогично поступим для остальных типов.
  4. Выполним соединение отфильтрованных временных таблиц с реальными табличными частями.

Пример реализации части такого пакета запросов:


// Помещаем все основания во временную таблицу
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Док.ОснованиеДокумент КАК СсылкаОснование
ПОМЕСТИТЬ ВТ_ВсеОснования
ИЗ
    Документ.ЗаказКлиента КАК Док
ГДЕ
    Док.ОснованиеДокумент <> ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка);

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

Важные нюансы работы с типами

Проанализируем еще несколько инструментов, которые предоставляет платформа для решения подобных задач:

Функция ТИПЗНАЧЕНИЯ и ТИП: В запросах можно использовать конструкцию ТИПЗНАЧЕНИЯ(Реквизит) = ТИП(Документ.ИмяДокумента). Однако стоит помнить, что оператор ССЫЛКА работает быстрее, так как он транслируется в прямой SQL-запрос к полю типа в таблице, в то время как ТИПЗНАЧЕНИЯ может потребовать обращения к внутренним таблицам метаданных 1С.

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

Динамическое построение запроса: Если ваш реквизит включает в себя десятки типов документов, использование ОБЪЕДИНИТЬ ВСЕ для каждого из них может перегрузить планировщик SQL-сервера. В таких случаях лучше программно в коде 1С проанализировать, документы каких типов реально присутствуют в выборке, и сформировать текст запроса только для этих типов. Это позволит избежать выполнения «пустых» операций сканирования таблиц, в которых заведомо нет нужных данных.

Обработка пустых ссылок: При проверке типа всегда учитывайте возможность наличия пустой ссылки или значения Неопределено. В запросах рекомендуется явно отсекать такие значения, чтобы избежать попадания лишних записей в результат при использовании соединений.

Подводя итог, можно сказать: для простых задач с 2-3 типами документов идеально подходит ОБЪЕДИНИТЬ ВСЕ. Для высоконагруженных систем и сложных отчетов следует отдавать предпочтение работе через временные таблицы и предварительную фильтрацию ссылок по типам.

← На главную