【问题标题】:SQL add filter only if a variable is not null仅当变量不为空时 SQL 添加过滤器
【发布时间】:2016-08-08 11:38:58
【问题描述】:

您好,我有如下疑问:

    SELECT  route_id [ROUTE_ID]
    FROM route_master(NOLOCK)
    WHERE  route_ou = 2
    AND   route_query = @l_s_query
    AND   lang_id  = 1

这里,只有当@l_s_query 不为空时,才应在 WHERE 子句中添加“AND route_query = @l_s_query”条件。我不想为@l_s_query 编写 IF ELSE 条件。有什么方法可以直接在 WHERE 子句中处理。谢谢。

【问题讨论】:

  • 或许... AND (route_query = @l_s_query OR @l_s_query IS NULL) ...?
  • 添加这个AND (@l_s_query IS NULL OR route_query = @l_s_query)
  • 标题中的问题“不为空”与标题中的问题“非空”不一致(因为我们称零长度字符串为“空”)。这就是为什么你有两个不同的答案,来自 sagi 和 Tamas。
  • 我以前在这样的查询中使用过 CASE 语句,在错误的情况下值是相同的,例如。 ... AND route_query = (CASE WHEN @l_s_query is not null THEN @l_s_query ELSE route_query END)

标签: sql sql-server


【解决方案1】:

您可以将您的要求翻译成:

SELECT  route_id [ROUTE_ID]
FROM route_master(NOLOCK)
WHERE  route_ou = 2
AND   (@l_s_query is null OR route_query = @l_s_query)
AND   lang_id  = 1
OPTION (RECOMPILE)

OPTION (RECOMPILE) 是可选的,但可以提供更好的执行计划,但会花费额外的编译时间,如关于主题 Dynamic Search Conditions in T‑SQL 的规范文章中所讨论的那样

或使用COALESCE() 来避免OR

WHERE  route_ou = 2
AND   COALESCE(@l_s_query,route_query) = route_query 
AND   lang_id  = 1

注意:正如@jarlh 所说,如果route_query 可以为空,这可能会由于空比较而导致一些问题,因此您可能需要使用第一个查询。

另一种选择是使用 UNION ALL 进行两个单独的查询,每个条件一个 -

SELECT .. FROM .. 
WHERE @l_s_query IS NULL
UNION ALL
SELECT .. FROM .. 
WHERE @l_s_query = route_query

在性能方面,只有最后一个会使用索引,我相信第一个会是最快的,但它可能会根据索引、表 ETC 的大小而改变..

【讨论】:

  • 第二次查询对于 route_query 中的 NULL 值有点不同。
  • @jarlh 是的。我对此添加了评论:)
  • 性能影响如何?这种表达方式不会阻止索引的使用,还是最新版本的 mssql 足够聪明来解决这个问题?我记得有时需要写两份这样的SELECTs,一份带有 WHERE 子句中的参数,另一份没有,包裹在 IF ... ELSE ... END
  • COALESCE(@l_s_query,route_query) = route_query ,刚刚发现第一手资料,如果值为 null 并且搜索参数为 null,这可能会导致问题, null = null 似乎不会评估为 true .
【解决方案2】:

只有当@l_s_query 不为空时,才应在 WHERE 子句中添加“AND route_query = @l_s_query”条件。

    WHERE  route_ou = 2
    AND   (  (@l_s_query IS NOT NULL AND route_query = @l_s_query ) OR
              @l_s_query IS NULL ) 
    AND   lang_id  = 1

【讨论】:

    【解决方案3】:

    这里有一个更好的处理方式:使用LEN(ISNULL)... OR:

    AND (LEN(ISNULL(@l_s_query,'')) = 0 OR route_query = @l_s_query)
    

    【讨论】:

      【解决方案4】:

      您可以使用 OR 模拟 if-else:

      AND ((0 = len(@l_s_query) OR @l_s_query IS NULL OR route_query = @l_s_query)
      

      解释:

      • AND (...) - 需要括号才能仅针对该谓词应用非空检查
      • 0 < len(@l_s_query) - 是一种确定varchar-s 非空的方法。

      【讨论】:

      • 如果@l_s_queryNULL 或为空,您的查询将返回零个结果。
      • 确实,OR 是正确的后备运算符。相应地修复了代码。
      • 您的语法已关闭。我想你缺少一个操作员。不过,IS EMPTY 似乎并不存在。如果@l_s_query 不为空,则不会针对route_query 进行检查。
      • 对,也修复了它们。如果 @l_s_queryroute_query 进行检查,当且仅当它不为空或 null 时。
      【解决方案5】:
      SELECT  route_id [ROUTE_ID]
      FROM route_master(NOLOCK)
      WHERE  route_ou = 2
      AND   (route_query = @l_s_query AND @l_s_query IS NOT NULL)
      AND   lang_id  = 1
      

      【讨论】:

        猜你喜欢
        • 2019-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-05
        • 2022-09-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多