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

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

При разработке отчетов на Системе Компоновки Данных (СКД) мы часто сталкиваемся с ситуацией, когда «умные» механизмы платформы работают слишком агрессивно. Одна из распространенных проблем — когда пользовательский отбор, установленный в настройках отчета, принудительно «проталкивается» платформой внутрь запроса, ломая логику получения данных. Для быстрой отладки и анализа таких запросов в реальном времени удобно использовать инструмент Консоль запросов УФ, который поддерживает работу с временными таблицами и СКД — для этого подойдёт универсальная консоль запросов и СКД для разработчика.

Рассмотрим ситуацию, когда в запросе необходимо получить данные по конкретному, жестко заданному складу (например, из константы или предопределенного элемента), но при этом пользователю нужно оставить возможность фильтровать отчет по другим складам. Часто бывает, что при установке пользовательского отбора СКД накладывает его и на нашу таблицу с «фиксированным» складом, в результате чего данные исчезают или искажаются. Разберем подробно, почему так происходит и как с этим бороться.

Понимаем механику: почему СКД добавляет лишние отборы?

Прежде чем переходить к лечению, давайте поставим диагноз. Система Компоновки Данных спроектирована так, чтобы максимально оптимизировать запросы к базе данных. Когда в схеме компоновки включен флаг Автозаполнение (он включен по умолчанию), система анализирует текст запроса. Если же вы работаете с нетипичными источниками, стоит учитывать особенности оптимизации отчетов с набором данных - объект, где механизмы фильтрации могут работать иначе.

Если СКД видит поле, путь к которому совпадает с полем отбора (например, Склад), она пытается применить условие фильтрации ко всем таблицам в запросе, где это поле встречается. Более того, платформа старается поместить отбор как можно «глубже» — например, в параметры виртуальной таблицы остатков, чтобы СУБД вернула уже отфильтрованную выборку. Подобная логика часто востребована, когда нужно передать динамический список в отчет СКД с сохранением всех наложенных пользователем ограничений.

В нашем случае это поведение становится вредным. У нас есть логика:

  1. Есть выборка остатков, которая должна быть строго ограничена определенным складом (например, складом брака или складом готовой продукции, заданным в константе).
  2. Есть общий список товаров, который пользователь хочет фильтровать по своему усмотрению.

Когда пользователь ставит отбор «Склад = Основной», СКД видит поле Склад в нашей подзапросе к константе или в параметрах виртуальной таблицы и добавляет туда условие: И Склад = &П_СкладПользователя. Это приводит к конфликту условий и пустым результатам.

Решение 1: Полный контроль через отключение Автозаполнения

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

Давайте выполним следующие действия:

  1. Откройте конструктор схемы компоновки данных.
  2. Перейдите на закладку Наборы данных.
  3. В свойствах запроса снимите галочку Автозаполнение.

Теперь, когда автозаполнение отключено, СКД перестает самостоятельно дописывать поля и отборы в итоговый SQL-запрос. Это означает, что мы должны вручную указать системе, где именно в тексте запроса можно вставлять пользовательские поля, отборы и сортировки. Для этого используются расширения языка запросов в фигурных скобках {}.

Рассмотрим пример запроса, адаптированного под ручное управление:


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

Разберем важные моменты в этом коде:

В контексте нашей проблемы: если мы хотим, чтобы в конкретной таблице отбор по складу игнорировался, мы просто не указываем расширение {Склад} внутри параметров этой конкретной таблицы или условия соединения. Таким образом, глобальный отбор будет применен только в секцию ГДЕ основного запроса (если мы это разрешили), но не сломает логику вложенного запроса с константой.

Решение 2: Использование псевдонимов (Алиасов)

Если отключение автозаполнения кажется слишком радикальной мерой (ведь придется вручную прописывать все поля), можно воспользоваться хитростью с псевдонимами. СКД связывает поля по их именам (путям к данным).

Суть метода заключается в том, чтобы «обмануть» СКД, дав полю в проблемной части запроса другое имя. Давайте посмотрим, как это сделать:

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

Пример изменения запроса:


ВЫБРАТЬ
    ...
    ТаблицаСкладов.Склад КАК СкладТехнический
ИЗ
    ...

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

Решение 3: Управление через параметры виртуальной таблицы

Иногда достаточно просто явно указать, какой параметр за что отвечает, используя расширения прямо внутри параметров виртуальной таблицы при включенном автозаполнении. Однако этот метод работает не всегда стабильно. В самых сложных архитектурных задачах иногда даже приходится использовать две разных схемы в отчете СКД, чтобы полностью разделить подготовку данных и их финальную фильтрацию.

Синтаксис выглядит так:


РегистрНакопления.ТоварыНаСкладах.Остатки(
    &Период,
    Склад = &НужныйСклад {Склад.* КАК Склад}
)

Здесь инструкция {Склад.* КАК Склад} говорит компоновщику: «Если есть отбор по Складу, добавь его именно сюда». Если эту инструкцию убрать, теоретически СКД не должна добавлять отбор в параметры ВТ. Но на практике, если включено автозаполнение, платформа может добавить условие в секцию ГДЕ, что все равно отфильтрует результат.

Резюме

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

Если же отчет простой, попробуйте сначала метод с псевдонимами (переименованием полей) — это часто помогает разорвать связь между пользовательским отбором и служебными полями запроса без лишних трудозатрат.

← На главную