При разработке отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда запрос состоит из пакета с несколькими временными таблицами. Например, выбираются обороты из двух разных регистров накопления, где измерения имеют одинаковые наименования: Номенклатура, Склад или Организация. Нередко по бизнес-логике требуется, чтобы пользовательский отбор по полю накладывался только на первую таблицу пакета, а вторая таблица оставалась нетронутой и рассчитывала общие или базовые показатели без фильтрации. Однако СКД по умолчанию стремится применить отборы во все части запроса, где обнаружены совпадающие имена полей.
Проанализируем причины такого поведения платформы 1С:Предприятие и разберем проверенные способы решения этой задачи по шагам.
Платформа использует механизм глубокой оптимизации запросов (push-down предикатов). Если в схеме компоновки включен механизм Автозаполнение, генератор запросов СКД детально анализирует весь пакет. Если пользователь в настройках отчета указывает отбор по определенному измерению, платформа автоматически пытается «протолкнуть» это условие как можно глубже — непосредственно в параметры виртуальных таблиц (в параметр Условие) и в секции ГДЕ всех временных таблиц пакета, где встречаются такие же поля. Кроме того, если во временной таблице поле связывается через ВНУТРЕННЕЕ СОЕДИНЕНИЕ с отфильтрованной таблицей, СКД также стремится продублировать фильтр во избежание считывания лишних строк.
Рассмотрим подробнее способы, позволяющие обойти автоматическое наложение условий и управлять поведением СКД.
Самый простой, быстрый и надежный подход — исключить совпадение имен полей. Если платформа не найдет поле с тем же именем, она не сможет сопоставить его с пользовательским отбором.
Разберем по шагам, как это реализовать:
Номенклатура укажем НоменклатураБезОтбора).Номенклатура из первой таблицы, к которому и привяжется фильтр отчета.Когда требуется полный контроль над текстом формируемого запроса, лучшим решением выступает отключение стандартного механизма автозаполнения. Выясним, как работает этот механизм.
По умолчанию в тексте запроса СКД стоит признак {// ...} и включен флажок Автозаполнение. Если снять этот флаг, СКД перестанет автоматически модифицировать секции запроса, но разработчику потребуется явно описать доступные поля выборки и места применения условий с помощью синтаксиса фигурных скобок:
{ГДЕ ...} или передадим условие внутрь параметров виртуальной таблицы через синтаксис расширения языка запросов СКД:
ВЫБРАТЬ
Таблица1.Номенклатура КАК Номенклатура,
Таблица1.КоличествоОборот КАК Количество
ПОМЕСТИТЬ ВТ_СОтбором
ИЗ
РегистрНакопления.Продажи.Обороты(, , , {Номенклатура.* КАК Номенклатура}) КАК Таблица1
;
Если изменять структуру полей нежелательно, а отключать автозаполнение слишком трудоемко из-за большого объема запроса, применим прием «разрыва связи» поля с метаданными. Для этого измерение во второй временной таблице оборачивается в простое логическое или системное выражение.
Посмотрим на пример такого кода:
ВЫБРАТЬ
ВЫБОР
КОГДА ИСТИНА ТОГДА Таблица2.Номенклатура
ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
КОНЕЦ КАК Номенклатура,
Таблица2.СуммаОборот КАК Сумма
ПОМЕСТИТЬ ВТ_БезОтбора
ИЗ
РегистрНакопления.Продажи.Обороты() КАК Таблица2
;
При таком подходе имя поля Номенклатура сохраняется, однако оптимизатор СКД больше не может сопоставить выражение напрямую с измерением виртуальной таблицы источника и не внедряет предикат отбора в параметры виртуальной таблицы или в секцию ГДЕ.
Вместо сложного пакета временных таблиц можно разделить логику на два независимых набора данных типа Набор данных - запрос:
В такой архитектуре пользовательский отбор накладывается исключительно на поля первого набора данных, а второй набор выполняется полностью независимо и возвращает данные без фильтрации.