Как запретить СКД автоматически накладывать отбор на временные таблицы запроса?

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

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

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

Причина автоматического наложения отборов

Проанализируем работу механизма автозаполнения СКД. По умолчанию для набора данных типа Запрос включен флаг Автозаполнение. Данный механизм оптимизирует выполнение запросов на уровне СУБД (механизм Pushdown): платформа находит в тексте пакета все поля, имена которых совпадают с полями отбора, и автоматически дописывает условия фильтрации во временные таблицы.

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

Способ 1. Использование расширения языка запросов СКД и псевдонимов

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

  1. Переименуем поля во временной таблице или зададим им уникальные псевдонимы в блоке расширения СКД.
  2. Опишем секцию {ГДЕ ...} явно только для той таблицы, к которой должен применяться пользовательский фильтр.

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


ВЫБРАТЬ
    ПродажиОбороты.Контрагент КАК Контрагент,
    ПродажиОбороты.КоличествоОборот КАК КоличествоОборот
ПОМЕСТИТЬ ВТ
{ВЫБРАТЬ
    Контрагент.* КАК КонтрагентИсходный}
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , {(Контрагент) КАК КонтрагентИсходный}) КАК ПродажиОбороты
ГДЕ
    НЕ ПродажиОбороты.Контрагент = &ПустойКонтрагент
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВЫБОР
        КОГДА ВТ.Контрагент.ГоловнойКонтрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
            ТОГДА ВТ.Контрагент
        ИНАЧЕ ВТ.Контрагент.ГоловнойКонтрагент
    КОНЕЦ КАК Контрагент,
    СУММА(ВТ.КоличествоОборот) КАК КоличествоОборот
{ВЫБРАТЬ
    Контрагент.*,
    КоличествоОборот}
ИЗ
    ВТ КАК ВТ
{ГДЕ
    (ВЫБОР
        КОГДА ВТ.Контрагент.ГоловнойКонтрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
            ТОГДА ВТ.Контрагент
        ИНАЧЕ ВТ.Контрагент.ГоловнойКонтрагент
    КОНЕЦ).* КАК Контрагент}
СГРУППИРОВАТЬ ПО
    ВЫБОР
        КОГДА ВТ.Контрагент.ГоловнойКонтрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
            ТОГДА ВТ.Контрагент
        ИНАЧЕ ВТ.Контрагент.ГоловнойКонтрагент
    КОНЕЦ

В данном примере поле во временной таблице объявлено в секции расширения как КонтрагентИсходный. В результате стандартный пользовательский отбор по полю Контрагент будет перехвачен исключительно конструкцией {ГДЕ ...} второго запроса и не повлияет на наполнение временной таблицы ВТ.

Способ 2. Отключение флага «Автозаполнение» и ручное описание полей

Разберем альтернативный вариант, когда требуется полный контроль над всеми полями и условиями компоновки:

  1. На вкладке Набор данных в нижней части окна редактора запроса снимем флаг Автозаполнение.
  2. Вручную опишем все доступные поля выборки и отбора с помощью фигурных скобок {}.
  3. Секцию {ГДЕ ...} пропишем исключительно во втором запросе пакета, оставив первый запрос без условий фильтрации.

Посмотрим на структуру такого запроса:


ВЫБРАТЬ
    ПродажиОбороты.Контрагент КАК Контрагент,
    ПродажиОбороты.КоличествоОборот КАК КоличествоОборот,
    ПродажиОбороты.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ
ИЗ
    РегистрНакопления.Продажи.Обороты({(&НачалоПериода)}, {(&КонецПериода)}, , ) КАК ПродажиОбороты
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.Контрагент КАК Контрагент,
    ВТ.КоличествоОборот КАК КоличествоОборот
{ВЫБРАТЬ
    Контрагент.*,
    КоличествоОборот}
ИЗ
    ВТ КАК ВТ
{ГДЕ
    ВТ.Номенклатура.*}

При такой схеме СКД физически не сможет добавить условие отбора по номенклатуре в первую таблицу пакета, так как секция расширения {ГДЕ ВТ.Номенклатура.*} определена строго для итогового запроса.

Способ 3. Перенос условий в вычисляемые поля

Проанализируем еще одну типовую методику, позволяющую исключить проталкивание отборов в СУБД:

  1. В основном запросе выбираем исходные данные без сложных выражений подмены.
  2. На вкладке Вычисляемые поля схемы компоновки данных создаем новое поле (например, ГоловнойКонтрагент) и прописываем выражение:

    ВЫБОР КОГДА Контрагент.ГоловнойКонтрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) ТОГДА Контрагент ИНАЧЕ Контрагент.ГоловнойКонтрагент КОНЕЦ

  3. В настройках отчета группировки и пользовательские отборы настраиваем по этому вычисляемому полю.

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

Нюансы и ограничения производительности

Выясним важные технические особенности описанных подходов:

  1. Нагрузка на СУБД: Если временная таблица обращается к большому объему данных, полное отключение отборов на первом шаге может привести к чтению лишних страниц данных и повышенному потреблению оперативной памяти. Используйте этот прием только тогда, когда получение полных данных действительно необходимо для расчетов.
  2. Однородность типов в выражениях ВЫБОР: При использовании условий {ГДЕ (ВЫБОР ...) } следите за тем, чтобы все ветки ТОГДА и ИНАЧЕ возвращали значения одинакового ссылочного типа, иначе генератор макета может выдать синтаксическую ошибку при формировании результирующего SQL-запроса.
← На главную