在SQL查询中使用动态条件

时间:2011-03-03 22:55:38

标签: sql sql-server optimization

如果我有一个运行带有可选参数的搜索的查询,我通常的方法是传入NULL以获取任何未使用的条件,并且有WHERE子句看起来像

WHERE (@Param IS NULL OR Field=@Param) AND (@Param2 IS NULL OR Field2=@Param2)

如果我的条件可能要稍微复杂一些,比如LIKE条款,SQL Server将评估IS NULL然后短路更复杂的条件?我是否可以在执行计划中查看是否存在?这种行为是否依赖于优化器选择的计划,这样我的开发和生产环境中的答案可能会有所不同(我有限制地查看生产中发生了什么,所以我希望行为一致)

3 个答案:

答案 0 :(得分:2)

请参阅this answer有关基于参数的查询的类似问题。

在他的回答中,他链接到一篇优秀的文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog

答案 1 :(得分:0)

我使用CASE语句。

所以你的是这样的:

WHERE (@Param IS NULL OR Field=@Param) AND (@Param2 IS NULL OR Field2=@Param2)

我会这样写:

WHERE CASE WHEN @Param IS NULL THEN 1 ELSE Field END = CASE WHEN @Param IS NULL THEN 1 ELSE @Param END AND  
CASE WHEN @Param2 IS NULL THEN 1 ELSE Field2 END = CASE WHEN @Param2 IS NULL THEN 1 ELSE @Param2 END

查看您获得的查询执行计划,在很多情况下,当您使用OR条件时,查询优化器使用表扫描。您也可以将'='替换为'like'等,实际上您甚至可以将其包含在case语句中。因此,您可以将{='替换为CASE WHEN @Param3 = 'eq' THEN = ELSE LIKE END

希望这有帮助。

答案 2 :(得分:0)

我找到了一个更实用的解决方案,它避免了使用动态SQL。

假设您有一个位字段,参数为1、0或(null =两者)。然后使用以下SQL:

在a.FIELD = CASE当ISNULL(@ PARAM,-1)=-1的情况下,然后a.FIELD ELSE @PARAM结束

换句话说:如果您不为@param提供显式值,则告诉A.field = a.field始终为真。对于可为空的字段,您需要在该字段上应用ISNULL,以免null = null不会通过。

示例:在INT字段上可以为空,

AND ISNULL(a.CALL_GENERAL_REQUIREMENTS,-1)=CASE WHEN ISNULL(@CALL_GENERAL_REQUIREMENTS,-2)=-2 THEN ISNULL(a.CALL_GENERAL_REQUIREMENTS,-1) ELSE @CALL_GENERAL_REQUIREMENTS END

如您所见,我将-2应用于参数@CALL_GENERAL_REQUIREMENTS的空值,这是因为要选择的实际值可以为0(未传递),1(已传递),-1(尚未评估)。因此,-2表示请勿在此字段上选择

可为空的字符串字段的示例:

AND ISNULL(a.CALL_RESULT,'')=CASE WHEN ISNULL(@CALL_RESULT,'')='' THEN ISNULL(a.CALL_RESULT,'') ELSE @CALL_RESULT END

所有功能都是一种魅力,并且避免了在创建带有串联的动态SQL字符串时的麻烦,并且不需要分配特定权限就可以运行exec语句。

希望这对任何人都有帮助。

祝你有美好的一天