Современные BI- и CRM-системы часто требуют реализовать пользовательские фильтры: важно гибко сочетать произвольные условия (по дате, полу, статусу, тегам), а также правильно пересекать и объединять их на SQL-языке. Получившийся код должен быть читаемым, легко изменяемым, и давать ожидаемый результат.
Часто разработчики "на лету" формируют WHERE с множеством AND/OR из пользовательских фильтров, что приводит к логическим ошибкам и сложным для обслуживания запросам. Проблема усугубляется, если значения фильтров могут отсутствовать или комбинироваться с IN/EXISTS/LIKE.
Для динамических фильтров удобен паттерн "условие с OR всегда TRUE, если значение не задано":
SELECT * FROM users WHERE (status = @status OR @status IS NULL) AND (gender = @gender OR @gender IS NULL) AND (created >= @from_date OR @from_date IS NULL) AND (city IN (@cities) OR @cities IS NULL);
Либо с помощью динамического SQL:
DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM users WHERE 1=1'; IF @status IS NOT NULL SET @sql += N' AND status = @status'; IF @gender IS NOT NULL SET @sql += N' AND gender = @gender'; -- ... EXEC sp_executesql @sql, N'@status NVARCHAR(10),@gender NVARCHAR(10)', @status, @gender;
Ключевые особенности:
Можно ли использовать WHERE 1=1 везде вместо проверки наличия условий?
Нет, 1=1 только стартовое условие для конкатенации WHERE — оно не заменяет фильтры, а используется исключительно для удобства генерации запросов.
Какие проблемы могут возникнуть, если в IN () попадет пустой список?
IN (NULL) или IN () всегда возвращает false и выдает пустой набор, даже при отсутствии фильтра. Для корректной работы следует отдельно проверять пустоту списка и не включать условие вообще.
Как повлияют подобные конструкции на использование индексов и производительность?
Если фильтры реализованы с OR или NULL-проверками, многие СУБД перестанут эффективно использовать индексы, либо выполнится скан всей таблицы. Стоит применять подходы с dynamic SQL или фильтрами с помощью параметризованных запросов, чтобы планировщик смог выбрать индекс.
Классический отчет с 10 фильтрами, код формирует WHERE с множеством OR — при отсутствии нескольких фильтров в результате отдается пустой набор или слишком большой скан, нагрузка на сервер возрастает в разы
Плюсы:
Отдельная функция формирует фильтры только по заданным параметрам, и только для каждой группы условий включается отдельный JOIN/FILTER. Where не содержит OR и лишних проверок на NULL.
Плюсы: