2013-07-23 3 views
2

Я создаю инструмент отчетности, в котором пользователь может выбрать оператора и 2 значения для фильтрации.T-SQL: фильтр с динамическим оператором сравнения (=, =, ...)

Моя основная таблица:

UserID  UserName 
------------------------------- 
1   User1 
2   User2 
3   User3 
4   User4 
5   User5 

Пользователь может выбрать оператор, который я хотел бы перевести так:

Option  SQL Operator 
------------------------------ 
between   column between x and y 
like   column '%' + x + '%' 
greater than column > x 
less than  column < x 
equal to  column = x 
not equal to column <> x 

Я думал о чем-то подобным:

... column = ISNULL(@parameter, column) 

в том смысле, что если вы передадите что-то или ничего, он все равно запросит правильно.

Вот TSQL Играю с (** НЕ РАБОТАЕТ *):

declare @bwValue1 varchar(200) = '2', --between value 1 
@bwValue2 varchar(200) = '4'; --between value 2 

select * from users where 
(UserID BETWEEN @bwValue1 AND @bwValue2 
OR UserID != @bwValue1 
OR UserID = @bwValue1 
OR UserID < @bwValue1 
OR UserID > @bwValue1 
OR UserID LIKE '%' + @bwValue1 + '%'); 

есть способ, чтобы написать TSQL, который не может правильно оценить заявление независимо от того, какой оператор выбран ?

* Окончательный ответ *

Вот что я закончил с для тех, кто любопытно:

declare @fn varchar(200) = 'carl', 
    @Op varchar(3) = 'bw', 
    @bwValue1 varchar(200) = '978', 
    @bwValue2 varchar(200) = '2000' 

select * from users where userfirstname like '%' + @fn + '%' 
     AND ((@Op = 'eq' AND (userid = @bwValue1)) 
OR (@Op = 'neq' AND (userid <> @bwValue1)) 
OR (@Op = 'lt' AND (userid < @bwValue1)) 
OR (@Op = 'gt' AND (userid > @bwValue1)) 
OR (@Op = 'li' AND (userid like '%' + @bwValue1 + '%')) 
OR (@Op = 'bw' AND (userid between @bwValue1 and @bwValue2))) 
+0

Создайте динамический SQL на основе указанных параметров. –

+0

Да, я пытался избежать этого. Требования говорят, что я должен использовать «Parameterized SQL», чтобы sql мог кэшировать sp для будущего использования, планирования выполнения и т. Д. – Losbear

+0

Я не думаю, что с таким множеством разнообразных параметров SQL может создать нормальный устойчивый план, который будет работать хорошо во всех сценарии. –

ответ

7

Dynamic SQL не означает, что вы не можете параметризовать его и кэширует планы. Работает нормально, потому что SQL Server не может отличить эту информацию. Если вы добавили несколько строк SQL (которые не содержат динамических литералов!), SQL Server будет рассматривать их как любой другой запрос. Он кэширует план. Конечно, каждый оператор приведет к другому плану. Возможно, это даже то, что вы хотите, если запрос может найти индекс таким образом!

Поэтому я рекомендую сделать запрос статическим, за исключением оператора.

Если вы не можете сделать это, и готовы отказаться от SARGability, сделайте следующее:

WHERE 0=0 
OR (Operator = '=' AND (A = B)) 
OR (Operator = '<' AND (A < B)) 
OR (Operator = '>' AND (A > B)) 
---... 

Ровно один из OR пунктов будет «активным» во время выполнения. Он по-прежнему выглядит читабельным и обслуживаемым.

+0

BETWEEN становится немного громоздким. Но это похоже на [мой ответ здесь] (http://stackoverflow.com/questions/10703072/passing-an-operand-as-an-sql-parameter). –

+1

Yep - это именно то, что я искал - спасибо за это! – Losbear

+0

вы сохранили мой день .. лучше установить AND cond перед использованием OR WHERE col1 = 'aaa' AND ( (Operator = '=' AND (A = B)) OR (Operator = '<' AND (A B)) –

0

Один дешевый способ, с которым я справился, - с помощью булевых компараторов указать, какое сравнение я хочу.

WHERE (A = B AND @equalOp = 1) OR (A > B AND @gtOp = 1) OR (A < B AND @ltOp = 1) 

Простой и даже не требует динамического SQL. Оптимизатор запросов должен помешать фактическому сравнению с использованием булевого для минимизации запроса. Я бы дважды проверял это, но для меня это работало!

+0

Спасибо, это было глупо от меня. :) Переключилось между полдюжины языков сегодня. – Codeman

Смежные вопросы