T-SQL:使用动态比较运算符过滤(=,< =,> =,...)

时间:2013-07-23 21:15:20

标签: sql-server tsql

我正在创建一个报告工具,用户可以选择一个操作符和2个值进行过滤。

我的基本表:

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)))

2 个答案:

答案 0 :(得分:7)

动态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子句中的一个在运行时将变为“活动”。它看起来仍然可读和可维护。

答案 1 :(得分:0)

我完成这个的一个便宜的方法是使用布尔比较器来指定我想要的比较。

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

简单,甚至不需要动态SQL。查询优化器应该通过使用布尔值来阻止实际比较以最小化查询。我会仔细检查这个,但它对我起了作用!