Как в запросе 1С сделать условие необязательным, если параметр не заполнен

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

При разработке отчетов или обработок на платформе 1С:Предприятие мы часто сталкиваемся с ситуацией, когда пользователю предоставляется несколько полей для фильтрации данных (например, Тип номенклатуры, Сотрудник, Отдел и Статус). Типичная проблема заключается в том, что если пользователь оставляет одно из полей пустым, запрос перестает возвращать данные, так как пытается найти записи с «пустым» значением, вместо того чтобы просто проигнорировать этот фильтр. В этой статье мы подробно разберем, как сделать условия в запросе гибкими и зависимыми от заполнения параметров.

Метод 1: Использование логических условий «ИЛИ» в тексте запроса

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

Рассмотрим пример реализации такого условия:


ГДЕ
    (&ЗнТип = Неопределено ИЛИ Номенклатура.Тип = &ЗнТип)
    И (&ЗнСотрудник = Неопределено ИЛИ Номенклатура.Сотрудник = &ЗнСотрудник)

Разберем по шагам, как это работает. Если мы передаем в параметр &ЗнТип значение Неопределено, то первая часть выражения (&ЗнТип = Неопределено) становится истинной. Согласно правилам булевой логики, для оператора ИЛИ достаточно истинности одного из выражений, поэтому все условие в скобках возвращает Истина для любой строки таблицы. Таким образом, фильтрация по этому полю фактически отключается.

Важный нюанс: при использовании этого метода нужно быть внимательным к тому, что именно считается «пустым» значением. Это может быть Неопределено, NULL или ПустаяСсылка соответствующего справочника. Рекомендуется перед установкой параметров в коде приводить незаполненные значения к единому виду.

Метод 2: Динамическая сборка текста запроса

Этот подход часто называют «классическим». Мы не пишем все условия сразу, а добавляем их в текст запроса только в том случае, если пользователь заполнил соответствующие поля на форме. Рассмотрим, как это выглядит в коде 1С:


ТекстЗапроса = 
"ВЫБРАТЬ
|   Номенклатура.Ссылка КАК Ссылка
|ИЗ
|   Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|   Истина"; // Базовое условие, чтобы дальше удобно добавлять "И ..."

Если ЗначениеЗаполнено(ЗнТип) Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |   И Номенклатура.Тип = &ЗнТип";
КонецЕсли;

Если ЗначениеЗаполнено(ЗнСотрудник) Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |   И Номенклатура.Сотрудник = &ЗнСотрудник";
КонецЕсли;

Запрос = Новый Запрос(ТекстЗапроса);
// Установка параметров только если они заполнены
Если ЗначениеЗаполнено(ЗнТип) Тогда
    Запрос.УстановитьПараметр("ЗнТип", ЗнТип);
КонецЕсли;

Посмотрим на преимущества этого метода. Во-первых, итоговый SQL-запрос получается максимально коротким и эффективным, так как в нем нет лишних проверок. Во-вторых, СУБД проще построить оптимальный план выполнения запроса. Однако есть и минус: такой код сложнее читать, и вы не сможете использовать стандартный Конструктор запроса для редактирования текста, который собирается по кусочкам.

Метод 3: Использование вспомогательных булевых параметров

Если вы хотите сохранить возможность работы с конструктором запроса, но метод с ИЛИ кажется вам громоздким, можно использовать флаги-маркеры. Мы передаем в запрос дополнительный параметр, который сообщает, нужно ли применять фильтр.

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


ГДЕ
    (НЕ &ОтборПоТипуИспользовать ИЛИ Номенклатура.Тип = &ЗнТип)
    И (НЕ &ОтборПоСотрудникуИспользовать ИЛИ Номенклатура.Сотрудник = &ЗнСотрудник)

В коде 1С это будет выглядеть следующим образом:


Запрос.УстановитьПараметр("ЗнТип", ЗнТип);
Запрос.УстановитьПараметр("ОтборПоТипуИспользовать", ЗначениеЗаполнено(ЗнТип));

Этот метод объединяет наглядность первого способа и строгость логики. Мы явно управляем включением и выключением каждого условия.

Метод 4: Использование конструкции «ВЫБОР КОГДА»

Иногда разработчики применяют оператор ВЫБОР прямо в секции ГДЕ. Выясним причину популярности и недостатки этого решения. Пример реализации:


ГДЕ
    ВЫБОР  
        КОГДА &ЗнТипПусто = ЛОЖЬ
            ТОГДА Номенклатура.Тип = &ЗнТип
        ИНАЧЕ ИСТИНА
    КОНЕЦ

Хотя такой подход кажется логичным, с точки зрения производительности он может быть опасен. Для СУБД (SQL Server или PostgreSQL) конструкции ВЫБОР внутри условий часто становятся «черным ящиком». Это может привести к тому, что индексы по полю Тип не будут использованы, и система начнет полное сканирование таблицы (Table Scan), что существенно замедлит работу базы на больших объемах данных.

Метод 5: Система компоновки данных (СКД)

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

  1. Вы описываете запрос в схеме компоновки данных.
  2. В секции условий используете стандартные параметры или добавляете поля в список доступных отборов.
  3. Если пользователь не установил флажок отбора в настройках отчета, СКД автоматически исключит это условие из итогового SQL-запроса.

Даже если вам не нужно выводить отчет на экран, вы можете программно инициализировать процессор компоновки, передать туда параметры и получить результат в таблицу значений. Это избавляет программиста от рутинной проверки Если ЗначениеЗаполнено(...) Тогда.

Метод 6: Схема запроса (QuerySchema)

Для продвинутых задач автоматизации в платформе 8.3 предусмотрен объект СхемаЗапроса. Он позволяет программно разбирать запрос на составляющие (выбираемые поля, источники, условия) и модифицировать их как объекты, а не как строки.

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


Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(ИсходныйТекст);
Пакет = Схема.ПакетЗапросов[0];

Если ЗначениеЗаполнено(ЗнТип) Тогда
    Пакет.Условия.Добавить("Номенклатура.Тип = &ЗнТип");
КонецЕсли;

ТекстРезультата = Схема.ПолучитьТекстЗапроса();

Этот метод является наиболее надежным, так как исключает ошибки синтаксиса при склейке строк (например, потерю пробела или лишнее «И»).

Проблема производительности и SARGability

Разберем важный технический аспект. В SQL существует понятие SARGable (Search Argumentable) условий. Это условия, которые позволяют эффективно использовать индексы.

Когда мы пишем ГДЕ (&ПараметрПуст ИЛИ Поле = &Параметр), мы создаем «не-SARGable» условие. Современные оптимизаторы SQL умеют справляться с такой простой логикой, но при усложнении запроса (например, добавлении нескольких соединений ЛЕВОЕ СОЕДИНЕНИЕ) производительность может резко упасть.

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

Итоги и рекомендации

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

  1. Если вы делаете обычный отчет — используйте СКД. Это стандарт де-факто в современной разработке на 1С.
  2. Если вам нужен быстрый запрос в коде и условий немного — используйте Метод 3 (Булевы флаги), он сохраняет читаемость и дружит с конструктором.
  3. Если условий очень много и важна производительность — используйте динамическую сборку текста или Схему запроса.
  4. Всегда проверяйте, что именно вы передаете в параметры. Помните, что для 1С Неопределено, NULL и пустая ссылка — это разные значения. Перед запросом приводите пустые поля ввода к Неопределено для единообразия.

Выяснив эти особенности и выбрав подходящий метод, вы сможете создавать гибкие и производительные механизмы поиска и фильтрации данных в своих конфигурациях.

← На главную