Как в СКД объединить условия по "ИЛИ" для двух необязательных параметров?

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

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

Логика работы должна быть следующей:

  1. Если ни один параметр не заполнен — в отчет попадает вся номенклатура базы данных.
  2. Если заполнен только сегмент — выводятся товары из этого сегмента.
  3. Если указан только список номенклатуры — выводятся выбранные позиции.
  4. Если заполнены оба параметра — выборка должна объединяться по логическому «ИЛИ» (в результат попадают и товары из сегмента, и явно указанные позиции).

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

Выясняем причину: почему стандартные фигурные скобки {ГДЕ} работают не так, как ожидается

Обычно для реализации необязательных параметров в запросе СКД используется синтаксис расширения языка запросов:


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

При таком написании платформа ведет себя следующим образом:

Попытка написать логическое ИЛИ внутри фигурных скобок напрямую, например: {ГДЕ (Условие1 ИЛИ Условие2)}, приведет к синтаксической ошибке компилятора запроса СКД при попытке сформировать отчет с одним незаполненным параметром. Платформа просто не сможет корректно исключить пустую часть выражения.

Рассмотрим подробнее три проверенных способа решения этой проблемы.

---

Способ 1. Использование вспомогательных булевых флагов (Рекомендуемый вариант)

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

Давайте по шагам настроим эту схему.

Шаг 1. Настройка параметров на вкладке «Параметры» в схеме компоновки данных

Вкладка параметров в конструкторе СКД должна содержать четыре параметра:

  1. &СегментыНоменклатурыАкции — тип СправочникСсылка.СегментыНоменклатуры (или список значений). Снимаем флаг «Запрещать незаполненные значения».
  2. &Номенклатура — тип СправочникСсылка.Номенклатура (или список значений). Снимаем флаг «Запрещать незаполненные значения».
  3. &ОтборПоСегментуАктивен — вспомогательный параметр булевого типа. Устанавливаем флаг «Ограничение доступности» (скрываем его от пользователя). В колонку «Выражение» прописываем формулу: ЗначениеЗаполнено(&СегментыНоменклатурыАкции)
  4. &ОтборПоНоменклатуреАктивен — второй вспомогательный параметр булевого типа. Также устанавливаем ограничение доступности и прописываем выражение: ЗначениеЗаполнено(&Номенклатура)

Шаг 2. Написание текста запроса

Теперь мы можем написать обычное, статическое условие в секции ГДЕ, используя законы булевой алгебры:


ВЫБРАТЬ
    НоменклатураСегмента.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ НоменклатураАкции
ИЗ
    РегистрСведений.НоменклатураСегмента КАК НоменклатураСегмента
ГДЕ
    // Ветка 1: Если оба параметра пусты — выбираем абсолютно все записи
    (НЕ &ОтборПоСегментуАктивен И НЕ &ОтборПоНоменклатуреАктивен)
    
    // Ветка 2: Если заполнен сегмент — берем по сегменту
    ИЛИ (&ОтборПоСегментуАктивен И НоменклатураСегмента.Сегмент В (&СегментыНоменклатурыАкции))
    
    // Ветка 3: Если заполнена номенклатура — берем по номенклатуре
    ИЛИ (&ОтборПоНоменклатуреАктивен И НоменклатураСегмента.Номенклатура В ИЕРАРХИИ (&Номенклатура))

Проанализируем работу данного запроса:

---

Способ 2. Исправление схемы запроса с ОБЪЕДИНИТЬ (UNION) во временных таблицах

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

Мы можем доработать этот подход до абсолютно корректного, задействовав те же булевые флаги активности параметров из Способа 1 для принудительного "гашения" ненужных пакетов запроса.

Рассмотрим этот код:


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

// Шаг 2. Получаем номенклатуру по списку.
// Аналогично, если параметр пуст, запрос вернет пустоту без нагрузки на СУБД.
ВЫБРАТЬ
    НоменклатураСпр.Ссылка КАК Номенклатура
ПОМЕСТИТЬ НоменклатураСправочник
ИЗ
    Справочник.Номенклатура КАК НоменклатураСпр
ГДЕ
    &ОтборПоНоменклатуреАктивен 
    И НоменклатураСпр.Ссылка В ИЕРАРХИИ (&Номенклатура)
;

// Шаг 3. Финальное объединение данных
ВЫБРАТЬ Номенклатура ИЗ НоменклатураАкцииПром КАК Таб1

ОБЪЕДИНИТЬ

ВЫБРАТЬ Номенклатура ИЗ НоменклатураСправочник КАК Таб2

ОБЪЕДИНИТЬ

// Эта ветка сработает и вернет все данные только тогда, когда оба параметра пустые
ВЫБРАТЬ Спр.Ссылка 
ИЗ Справочник.Номенклатура КАК Спр 
ГДЕ (НЕ &ОтборПоСегментуАктивен И НЕ &ОтборПоНоменклатуреАктивен)

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

---

Способ 3. Перевод параметров в стандартные "Отборы" СКД (Стандарт 1С)

Стандарты разработки систем на платформе «1С:Предприятие 8» рекомендуют по возможности избегать явного программирования условий в текстах запросов через параметры, если задачу можно решить штатными механизмами отборов СКД. Платформа умеет самостоятельно оптимизировать такие выборки на уровне СУБД.

Давайте разберем, как реализовать аналогичную логику «ИЛИ» исключительно силами интерфейса настроек компоновки данных.

Шаг 1. Добавление полей в запрос

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    НоменклатураСегмента.Сегмент КАК Сегмент
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НоменклатураСегмента КАК НоменклатураСегмента
        ПО Номенклатура.Ссылка = НоменклатураСегмента.Номенклатура

Шаг 2. Настройка структуры отборов в СКД

Перейдем на вкладку «Настройки» в конструкторе схемы компоновки данных и откроем вкладку «Отбор»:

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

Как это будет работать на практике?

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

← На главную