Как в СКД наложить отбор на поле только в одном пакете запроса и проигнорировать его в другом?

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

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

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

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

Решение 1: Изоляция через изменение «Пути к данным»

Этот способ является наиболее простым в реализации и не требует глубокого изменения логики запроса. Разберем его по шагам:

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

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

Решение 2: Использование вкладки «Компоновка данных» в конструкторе запроса

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

  1. Откроем Конструктор запроса и перейдем на закладку Компоновка данных.
  2. В верхней части окна мы увидим список пакетов запроса. Выберем тот пакет, в котором отбор должен быть индивидуальным или отсутствовать.
  3. На закладке Поля для этого конкретного пакета можно задать уникальные псевдонимы, которые СКД воспримет как разные пути к данным.
  4. На закладке Условия можно явно указать, какие поля доступны для отбора именно в этом пакете.

Решение 3: Явное управление через фигурные скобки {}

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

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


// Пакет №1: Здесь отбор по номенклатуре НУЖЕН
ВЫБРАТЬ
    Продажи.Подразделение КАК Подразделение,
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.СуммаОборот КАК Сумма
ПОМЕСТИТЬ ВТ_ДетальныеДанные
ИЗ
    РегистрНакопления.Продажи.Обороты(&Начало, &Конец, , {Номенклатура.*}) КАК Продажи
;

////////////////////////////////////////////////////////////////////////////////
// Пакет №2: Здесь нам нужны итоги по подразделению БЕЗ учета отбора по номенклатуре
ВЫБРАТЬ
    ПродажиИтоги.Подразделение КАК Подразделение,
    ПродажиИтоги.СуммаОборот КАК СуммаИтого
ИЗ
    РегистрНакопления.Продажи.Обороты(&Начало, &Конец, , ) КАК ПродажиИтоги

В данном примере в первом пакете мы использовали конструкцию {Номенклатура.*} в параметрах виртуальной таблицы. Это говорит системе: «Если пользователь выбрал номенклатуру, подставь её сюда». Во втором пакете параметры пусты, и СКД не будет принудительно внедрять туда условия, если мы правильно настроили пути к данным или роли полей.

Решение 4: Использование параметров вместо отборов

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

  1. Создадим в схеме СКД новый параметр, например, ВыбраннаяНоменклатура.
  2. Установим ему тип СправочникСсылка.Номенклатура (или СписокЗначений).
  3. В первом пакете запроса в параметрах виртуальной таблицы пропишем условие: Номенклатура В (&ВыбраннаяНоменклатура).
  4. Во втором пакете этот параметр просто не будем использовать.
  5. Чтобы пользователь не путался, стандартное поле Номенклатура на закладке «Наборы данных» можно отметить флажком Ограничение условия.

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

Сравнительный анализ и рекомендации

Проанализируем производительность. Использование нескольких наборов данных и их связь на вкладке Связи наборов данных (как сделал автор темы) — рабочее решение, но оно имеет «подводные камни». Связывание происходит на уровне 1С, а не SQL-сервера. Если в первом наборе данных тысячи строк, это может привести к значительному замедлению отчета.

Рекомендуемый алгоритм действий:

  1. Старайтесь решать задачу в рамках одного запроса с несколькими пакетами.
  2. Используйте вкладку Компоновка данных для разделения путей к полям в разных пакетах.
  3. Для виртуальных таблиц всегда явно прописывайте возможные отборы в фигурных скобках {} в тексте запроса, чтобы контролировать «протекание» фильтров.

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

← На главную