При разработке отчетов или обработок на платформе 1С:Предприятие мы часто сталкиваемся с ситуацией, когда пользователю предоставляется несколько полей для фильтрации данных (например, Тип номенклатуры, Сотрудник, Отдел и Статус). Типичная проблема заключается в том, что если пользователь оставляет одно из полей пустым, запрос перестает возвращать данные, так как пытается найти записи с «пустым» значением, вместо того чтобы просто проигнорировать этот фильтр. В этой статье мы подробно разберем, как сделать условия в запросе гибкими и зависимыми от заполнения параметров.
Проанализируем самый простой способ, который не требует изменения текста запроса в программном коде. Мы можем прописать логику проверки параметра прямо в секции ГДЕ. Суть метода заключается в том, что условие считается выполненным, если либо параметр не задан, либо поле базы данных совпадает с параметром.
Рассмотрим пример реализации такого условия:
ГДЕ
(&ЗнТип = Неопределено ИЛИ Номенклатура.Тип = &ЗнТип)
И (&ЗнСотрудник = Неопределено ИЛИ Номенклатура.Сотрудник = &ЗнСотрудник)
Разберем по шагам, как это работает. Если мы передаем в параметр &ЗнТип значение Неопределено, то первая часть выражения (&ЗнТип = Неопределено) становится истинной. Согласно правилам булевой логики, для оператора ИЛИ достаточно истинности одного из выражений, поэтому все условие в скобках возвращает Истина для любой строки таблицы. Таким образом, фильтрация по этому полю фактически отключается.
Важный нюанс: при использовании этого метода нужно быть внимательным к тому, что именно считается «пустым» значением. Это может быть Неопределено, NULL или ПустаяСсылка соответствующего справочника. Рекомендуется перед установкой параметров в коде приводить незаполненные значения к единому виду.
Этот подход часто называют «классическим». Мы не пишем все условия сразу, а добавляем их в текст запроса только в том случае, если пользователь заполнил соответствующие поля на форме. Рассмотрим, как это выглядит в коде 1С:
ТекстЗапроса =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Истина"; // Базовое условие, чтобы дальше удобно добавлять "И ..."
Если ЗначениеЗаполнено(ЗнТип) Тогда
ТекстЗапроса = ТекстЗапроса + "
| И Номенклатура.Тип = &ЗнТип";
КонецЕсли;
Если ЗначениеЗаполнено(ЗнСотрудник) Тогда
ТекстЗапроса = ТекстЗапроса + "
| И Номенклатура.Сотрудник = &ЗнСотрудник";
КонецЕсли;
Запрос = Новый Запрос(ТекстЗапроса);
// Установка параметров только если они заполнены
Если ЗначениеЗаполнено(ЗнТип) Тогда
Запрос.УстановитьПараметр("ЗнТип", ЗнТип);
КонецЕсли;
Посмотрим на преимущества этого метода. Во-первых, итоговый SQL-запрос получается максимально коротким и эффективным, так как в нем нет лишних проверок. Во-вторых, СУБД проще построить оптимальный план выполнения запроса. Однако есть и минус: такой код сложнее читать, и вы не сможете использовать стандартный Конструктор запроса для редактирования текста, который собирается по кусочкам.
Если вы хотите сохранить возможность работы с конструктором запроса, но метод с ИЛИ кажется вам громоздким, можно использовать флаги-маркеры. Мы передаем в запрос дополнительный параметр, который сообщает, нужно ли применять фильтр.
Проанализируем структуру такого запроса:
ГДЕ
(НЕ &ОтборПоТипуИспользовать ИЛИ Номенклатура.Тип = &ЗнТип)
И (НЕ &ОтборПоСотрудникуИспользовать ИЛИ Номенклатура.Сотрудник = &ЗнСотрудник)
В коде 1С это будет выглядеть следующим образом:
Запрос.УстановитьПараметр("ЗнТип", ЗнТип);
Запрос.УстановитьПараметр("ОтборПоТипуИспользовать", ЗначениеЗаполнено(ЗнТип));
Этот метод объединяет наглядность первого способа и строгость логики. Мы явно управляем включением и выключением каждого условия.
Иногда разработчики применяют оператор ВЫБОР прямо в секции ГДЕ. Выясним причину популярности и недостатки этого решения. Пример реализации:
ГДЕ
ВЫБОР
КОГДА &ЗнТипПусто = ЛОЖЬ
ТОГДА Номенклатура.Тип = &ЗнТип
ИНАЧЕ ИСТИНА
КОНЕЦ
Хотя такой подход кажется логичным, с точки зрения производительности он может быть опасен. Для СУБД (SQL Server или PostgreSQL) конструкции ВЫБОР внутри условий часто становятся «черным ящиком». Это может привести к тому, что индексы по полю Тип не будут использованы, и система начнет полное сканирование таблицы (Table Scan), что существенно замедлит работу базы на больших объемах данных.
Рассмотрим наиболее профессиональный и современный способ решения задачи. Если ваша задача позволяет использовать Систему компоновки данных, то проблема «пустых параметров» исчезает сама собой. СКД — это мощный движок, который автоматически генерирует текст запроса на основе настроек пользователя.
Даже если вам не нужно выводить отчет на экран, вы можете программно инициализировать процессор компоновки, передать туда параметры и получить результат в таблицу значений. Это избавляет программиста от рутинной проверки Если ЗначениеЗаполнено(...) Тогда.
Для продвинутых задач автоматизации в платформе 8.3 предусмотрен объект СхемаЗапроса. Он позволяет программно разбирать запрос на составляющие (выбираемые поля, источники, условия) и модифицировать их как объекты, а не как строки.
Посмотрим, как добавить условие программно, сохраняя чистоту кода:
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(ИсходныйТекст);
Пакет = Схема.ПакетЗапросов[0];
Если ЗначениеЗаполнено(ЗнТип) Тогда
Пакет.Условия.Добавить("Номенклатура.Тип = &ЗнТип");
КонецЕсли;
ТекстРезультата = Схема.ПолучитьТекстЗапроса();
Этот метод является наиболее надежным, так как исключает ошибки синтаксиса при склейке строк (например, потерю пробела или лишнее «И»).
Разберем важный технический аспект. В SQL существует понятие SARGable (Search Argumentable) условий. Это условия, которые позволяют эффективно использовать индексы.
Когда мы пишем ГДЕ (&ПараметрПуст ИЛИ Поле = &Параметр), мы создаем «не-SARGable» условие. Современные оптимизаторы SQL умеют справляться с такой простой логикой, но при усложнении запроса (например, добавлении нескольких соединений ЛЕВОЕ СОЕДИНЕНИЕ) производительность может резко упасть.
Рекомендация: если вы работаете с высоконагруженной системой или таблицами на миллионы записей, всегда отдавайте предпочтение динамической сборке текста или СКД. Эти методы гарантируют, что в итоговый запрос попадут только необходимые фильтры, что обеспечит максимальную скорость работы.
Проанализировав все возможные ситуации, можно вывести следующий алгоритм выбора решения:
Неопределено, NULL и пустая ссылка — это разные значения. Перед запросом приводите пустые поля ввода к Неопределено для единообразия.Выяснив эти особенности и выбрав подходящий метод, вы сможете создавать гибкие и производительные механизмы поиска и фильтрации данных в своих конфигурациях.