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

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

Часто при разработке отчетов и обработок в 1С возникает задача дополнить строки табличной части одного документа данными из табличной части документа-основания. Например, требуется получить поле ВидЦены из документа РеализацияТоваровУслуг для каждой строки табличной части документа ВозвратТоваровОтКлиента, где документ реализации указан построчно в реквизите ДокументРеализации (или ДокументОснование).

Разберем типичные ошибки, возникающие при попытке использовать вложенные подзапросы в списке полей, и рассмотрим правильные, производительные способы решения этой задачи с помощью механизмов языка запросов 1С.

Ограничения языка запросов 1С при работе с подзапросами

Посмотрим на попытку реализовать такую логику через скалярный подзапрос прямо в секции ВЫБРАТЬ:


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

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

Для сопоставления данных между табличными частями разных документов в 1С применяются конструкции соединений таблиц (ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ).

Базовый вариант: прямое левое соединение табличных частей

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


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

Обратим внимание на условие в секции ГДЕ: при фильтрации по дате документа из таблицы табличной части необходимо обращаться через точку к реквизиту шапки: ВозвратТоваров.Ссылка.Дата.

Оптимизация производительности запроса

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

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


ВЫБРАТЬ
    ВозвратТовары.Ссылка КАК ДокументВозврата,
    ВозвратТовары.НомерСтроки КАК НомерСтроки,
    ВозвратТовары.Номенклатура КАК Номенклатура,
    ВозвратТовары.Количество КАК Количество,
    ВозвратТовары.Цена КАК Цена,
    ВозвратТовары.Сумма КАК Сумма,
    ВозвратТовары.ДокументРеализации КАК ДокументРеализации,
    РеализацияТовары.ВидЦены КАК ВидЦены
ИЗ
    Документ.ВозвратТоваровОтКлиента КАК ВозвратШапка
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ВозвратТоваровОтКлиента.Товары КАК ВозвратТовары
        ПО ВозвратШапка.Ссылка = ВозвратТовары.Ссылка
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
        ПО (РеализацияТовары.Ссылка = ВЫРАЗИТЬ(ВозвратТовары.ДокументРеализации КАК Документ.РеализацияТоваровУслуг))
        И (РеализацияТовары.Номенклатура = ВозвратТовары.Номенклатура)
ГДЕ
    ВозвратШапка.Дата МЕЖДУ &НачалоПериода И &ОкончаниеПериода

Подводные камни и риски при соединении табличных частей

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

  1. Размножение строк (декартово произведение): Если в документе реализации одна и та же номенклатура встречается в нескольких строках (например, с разными ценами, складами или скидками), простое соединение по полю Номенклатура приведет к дублированию строк возврата в выборке.
  2. Учет дополнительных аналитических разрезов: Если в информационной базе включен учет по характеристикам, сериям или назначениям, условие соединения только по номенклатуре вернет неверные данные. В секцию ПО необходимо обязательно включать сопоставление по полям Характеристика, Серия и другим активным аналитикам.
  3. Составной тип реквизита основания: Реквизит ДокументРеализации часто имеет составной тип данных. Использование конструкции ВЫРАЗИТЬ(ВозвратТовары.ДокументРеализации КАК Документ.РеализацияТоваровУслуг) исключает лишние соединения со всеми остальными таблицами документов, входящих в составной тип.
  4. Служебные ключи строк: В типовых конфигурациях (например, 1С:УТ, 1С:КА, 1С:ERP) для точного связывания строк возврата с исходным документом продажи предусмотрены служебные реквизиты, такие как КлючСвязи, ИдентификаторСтроки или НомерСтрокиДокументаРеализации. Использование этих полей в условиях соединения гарантирует однозначное соответствие строк без риска дублирования.

Рекомендуемое решение через временные таблицы

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


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

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

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

Использование пакета запросов с временными таблицами позволяет оптимизатору СУБД построить эффективный план выполнения, а агрегатная функция МАКСИМУМ в группировке гарантирует, что количество строк в результирующем отчете в точности совпадет с количеством строк в исходном документе возврата.

← На главную