SQl select语句 - 将Case放在Where部分中

时间:2014-05-28 08:44:45

标签: sql case

您好我正在使用Visual Studio的Microsoft SQL服务器管理器,我有点坚持使用Select命令我正试图实现。

SELECT  ...               
FROM     ... 

WHERE  (t .companyID = @companyId) 
       AND (DATEDIFF(DateInterval.Day, @start, r.date) >= 0) 
       AND (DATEDIFF(DateInterval.Day, @end, r.date) <= 0) 
       // last row to add
       AND (CASE WHEN @status != 'show all' THEN r.poStatus = @status END) 

该命令运行良好但现在我还需要添加最后一行(用户可以选择状态,只显示具有选择状态的行,或者如果没有选择它将显示所有行 - 我有一个vb代码,在这种情况下显示所有&#34;值 所以我想做一个额外的术语,检查价值是否显示全部&#34;跳过这个,如果没有显示具有所选值的行,但我找不到合适的syntex来执行此操作,如果可能的话?

p.s我看到它并不是很清楚我所做的是什么&#39;显示所有&#39;是显示所有表,只有当其他所有表显示全部使用WHERE部分来选择表中的右行。

4 个答案:

答案 0 :(得分:2)

(CASE WHEN @status != 'show all' THEN r.poStatus = @status END) 

相当于

IF @status = 'show all' THEN 
    ;// no additional conditions
ELSE // so @status != 'show all'
    r.poStatus = @status
END IF;

所以你可以把它放在标准的逻辑条件下:

AND (@status = 'show all' OR (@status != 'show all' AND r.poStatus = @status))

答案 1 :(得分:1)

Where r.poStatus = 
    Case When @Status != 'Show all' Then @status 
         Else r.poStatus End

让我知道它是否有帮助!

答案 2 :(得分:1)

请尝试避免CASE并改为使用布尔条件。

SELECT * FROM yourTable
WHERE (t .companyID = @companyId) AND (DATEDIFF(DateInterval.Day, @start, r.date) >= 0)
AND (DATEDIFF(DateInterval.Day, @end, r.date) <= 0)
AND (@status = 'show all' OR r.poStatus = @status);

答案 3 :(得分:1)

我建议不要这样做,而是使用IF/ELSE块:

IF @Status = 'show all'
    BEGIN
        SELECT ...
        FROM ...
        WHERE   t .companyID = @companyId 
        AND     DATEDIFF(DateInterval.Day, @start, r.date) >= 0 
        AND     DATEDIFF(DateInterval.Day, @end, r.date) <= 0 
    END
ELSE
    BEGIN
        SELECT  ..
        FROM    ...
        WHERE   t .companyID = @companyId 
        AND     DATEDIFF(DateInterval.Day, @start, r.date) >= 0 
        AND     DATEDIFF(DateInterval.Day, @end, r.date) <= 0 
        AND     r.poStatus = @status

    END

原因是除非您使用OPTION (RECOMPILE)运行查询,否则查询将使用全表扫描,即使您通过了 @status' and poStatus`的值被索引,这将不是最佳的。选择表扫描而不是索引查找的原因是因为在编译时它不知道它是应该返回poStatus的所有值还是只返回一个值。

如果这是一个存储过程,或者通过sp_executesql传递,那么结果可能会更糟,在编译时该值将是已知的,因此查询 将根据参数值创建计划。但是,每次运行它都将使用第一次运行时的缓存计划,并且您可能会以次优的查询计划结束。

对于它的价值,这个谓词也不是很好,它不是sargable

AND     DATEDIFF(DateInterval.Day, @start, r.date) >= 0 
AND     DATEDIFF(DateInterval.Day, @end, r.date) <= 0 

因为您正在评估函数或r.date,所以您无法利用列上的任何索引。最好写成:

AND     r.Date >= @Start
AND     r.Date < DATEADD(DAY, 1, @End);

如果由于某种原因必须在一个查询中完成所有操作,那么如上所述,您应该使用查询提示OPTION (RECOMPILE)来确保在运行时编译查询,并且可以为给定的选择选择适当的计划价值@Status

SELECT  ..
FROM    ...
WHERE   t .companyID = @companyId 
AND     r.Date >= @Start
AND     r.Date < DATEADD(DAY, 1, @End);
AND     (r.poStatus = @status OR @Status = 'show all')
OPTION (RECOMPILE);