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

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

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

Проблема выбора источника из массива документов

Если мы работаем в контексте Библиотеки стандартных подсистем (БСП), в менеджер печати обычно передается массив ссылок МассивОбъектов. Проверять тип операции в коде через цикл (например, МассивОбъектов[0].ХозяйственнаяОперация) — неверная стратегия, так как документы в массиве могут иметь разные операции. Нам необходимо реализовать логику разделения потоков данных непосредственно внутри запроса.

Способ 1: Использование конструкции ВЫБОР КОГДА

Для простых случаев, когда нам нужно получить значение одного поля, которое может находиться либо в одной, либо в другой табличной части, можно использовать левое соединение с обеими таблицами и конструкцию ВЫБОР. Рассмотрим этот пример:


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

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

Способ 2: Использование ОБЪЕДИНИТЬ ВСЕ с фильтрацией

Проанализируем ситуацию, когда данные в разных ТЧ имеют разную структуру. Самый надежный способ — это объединение нескольких выборок, где каждая выборка жестко ограничена своим условием по хозяйственной операции. Это позволяет четко разделить логику получения данных.


ВЫБРАТЬ
    ТЧ_Товары.Ссылка КАК Ссылка,
    ТЧ_Товары.Номенклатура КАК Номенклатура,
    ТЧ_Товары.Количество КАК Количество,
    ТЧ_Товары.ФизическоеЛицо КАК ФизическоеЛицо
ПОМЕСТИТЬ ВТ_ОбщиеДанные
ИЗ
    Документ.СписаниеТоваров.Товары КАК ТЧ_Товары
ГДЕ
    ТЧ_Товары.Ссылка В(&МассивОбъектов)
    И ТЧ_Товары.Ссылка.ХозяйственнаяОперация = ЗНАЧЕНИЕ(Перечисление.ХозяйственныеОперации.СписаниеПоНормам)

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

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

В данном примере мы собираем данные в одну временную таблицу ВТ_ОбщиеДанные, приводя разные по смыслу поля к единому наименованию. Это значительно упрощает последующую работу с результатом запроса.

Способ 3: Распределение данных (сложный случай)

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

В этом случае проанализируем следующий алгоритм:

  1. Выгружаем данные о ценах и общих количествах из основной ТЧ во временную таблицу.
  2. Выгружаем данные о сотрудниках из дополнительной ТЧ в другую временную таблицу.
  3. Соединяем эти таблицы по полям Ссылка и Номенклатура.

// 1. Получаем цены и общие данные
ВЫБРАТЬ
    ТЧ.Ссылка КАК Ссылка,
    ТЧ.Номенклатура КАК Номенклатура,
    ТЧ.Цена КАК Цена,
    ТЧ.Количество КАК ОбщееКоличество
ПОМЕСТИТЬ ВТ_Цены
ИЗ
    Документ.РасходныйОрдер.Товары КАК ТЧ
ГДЕ
    ТЧ.Ссылка В(&МассивОбъектов);

// 2. Получаем список сотрудников
ВЫБРАТЬ
    ТЧ.Ссылка КАК Ссылка,
    ТЧ.Номенклатура КАК Номенклатура,
    ТЧ.ФизическоеЛицо КАК ФизическоеЛицо
ПОМЕСТИТЬ ВТ_Сотрудники
ИЗ
    Документ.РасходныйОрдер.Спецодежда КАК ТЧ
ГДЕ
    ТЧ.Ссылка В(&МассивОбъектов);

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

Важные рекомендации по оптимизации

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

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

← На главную