在WHERE子句中应用条件筛选

时间:2016-01-21 10:01:10

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

我在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

2 个答案:

答案 0 :(得分:4)

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

其次,请勿使用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

答案 1 :(得分:0)

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

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与自身进行比较,那当然总会导致匹配。

我个人更喜欢@jarlh在上面的评论中提出的方法。简单性使代码更容易遵循。

@jarlh示例

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

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