【问题标题】:Apply conditional filtering in WHERE clause在 WHERE 子句中应用条件过滤
【发布时间】:2016-01-21 10:01:09
【问题描述】:

我在下面的 SELECT 语句中加入了几个表,它有三个参数。

DECLARE @Jobid      INT=0,
        @leadid     INT=0,
        @employeeid INT=0

SELECT e.id,
       l.id,
       j.id,
       e.NAME,
       l.NAME,
       j.NAME
FROM   employee e
       INNER JOIN leads l
               ON e.leadid = l.id
       INNER JOIN Jobs j
               ON j.id = e.Jobid 

没有过滤也可以正常工作。

在 WHERE 子句中,我必须添加如下内容。如果三个 ID 中的任何一个大于零,那么我必须考虑 WHERE 子句中的过滤器;如果它等于零,我不会考虑那个特定条件。

If @jobid> 0
then introduce this condition in where clause (j.id=@jobid) 

If @leadid> 0
then introduce this condition in where clause (l.id=@leadid)

If @employeeid> 0
then introduce this condition in where clause (e.id=@employeeid)

我知道如何通过动态 SQL 来实现这一点,但我需要一个静态 SQL 语句来实现这一点。

我尝试了以下方法:

where 
((J.Id = @Jobid and @Jobid>0 )
or  @Jobid=0)
and (
(L.Id = @leadid and @leadid>0 )
or  @leadid=0
)
and (
(e.Id = @employeeid and @employeeid >0 )
or  @employeeid =0
)

但性能会受到影响。

请建议我在静态 SQL 中执行此操作的任何其他更好的方法,尤其是使用 Case When

【问题讨论】:

  • 查看answer
  • 只需(J.Id = @Jobid or @Jobid=0) 等也会这样做。 (不知道会不会更快...)
  • @Mihail:我不是在寻找动态 SQL
  • @jarlh:谢谢贾尔赫

标签: sql sql-server sql-server-2012


【解决方案1】:

首先,这个((J.Id = @Jobid and @Jobid>0) or @Jobid=0)可以替换
用这个(@Jobid = 0 or J.Id = @Jobid)。 请注意,由于 0 显然不是工作 ID(或员工或领导)的有效值,因此 and 部分无关紧要,因为任何记录都不会包含 0 的 ID。

其次,不要使用0作为无效值,而是使用null。它不会影响性能,但它是一种更好的编程习惯,因为0 在其他情况下很可能是一个有效值。

第三,众所周知,catch-all 查询会受到性能影响,尤其是在存储过程中,因为缓存的执行计划可能不是当前执行的最佳计划。据我所知,处理此问题的最佳方法是向查询添加重新编译提示,如 this articlethat article 中所建议的那样。

因此,我建议您的查询如下所示:

CREATE PROCEDURE <procedure name>
(
        @Jobid      INT=NULL,
        @leadid     INT=NULL,
        @employeeid INT=NULL
)
AS

SELECT e.id,
       l.id,
       j.id,
       e.NAME,
       l.NAME,
       j.NAME
FROM   employee e
       INNER JOIN leads l
               ON e.leadid = l.id
       INNER JOIN Jobs j
               ON j.id = e.Jobid 
WHERE (@Jobid IS NULL OR J.Id = @Jobid)
AND (@leadid IS NULL OR l.Id = @leadid)
AND (@employeeid IS NULL OR e.Id = @employeeid)
OPTION(RECOMPILE)

GO

选择性能通常会通过正确的表索引来提高。但是,正确索引需要并非所有开发人员都具备的知识。这是一个非常值得一读的主题。我会start here

【讨论】:

  • 非常感谢您的建议。我已经选择了目的地数据答案。无论如何我都会投赞成票。
【解决方案2】:

您可以像这样使用 CASE 表达式:

案例示例

WHERE
    CASE 
        WHEN @Jobid > 0 THEN @Jobid     -- When @Jobid supplied use it.
        ELSE J.id                       -- When not; return current value.
    END = J.id

当@Jiobid 超过 0 时,它与 J.id 进行比较。如果不是 J.id 则与自身进行比较,这当然总是会导致匹配。

我个人更喜欢上面 cmets 中 @jarlh 建议的方法。简单性使代码更容易理解。

@jarlh 示例

WHERE
    (J.Id = @Jobid or @Jobid=0)

如果这些方法不能提高您的表现,请尝试将您的架构和一些示例记录添加到问题中。您也可以考虑发布执行计划。

【讨论】:

  • 您还应该查看@ZoharPeled 的答案。他/她对 0 的使用提出了很好的观点。
  • 关于这个答案的一件事 - 在目标列(J.Id,在这种情况下)可以为空的情况下,它可能会导致不正确的结果,因为 null = null 将评估为假。除此之外,我在测试案例时看到性能没有变化......当版本时,所以这是一个关于作者认为什么更具可读性的问题。
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2019-03-11
  • 2012-12-06
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 2018-03-10
相关资源
最近更新 更多