SQL查询中where子句的CASE语句

时间:2014-09-16 15:26:07

标签: sql sql-server tsql crystal-reports

我正在尝试在我正在处理的查询的where子句中编写一个case语句。我正在导入Crystal报表中的代码,我基本上试图说明变量'type'是否设置为'create'在where子句中为此日期范围运行,否则运行不同的日期范围。它一直给我一个错误。我似乎无法确定我的语法有什么问题。帮助任何人?

DECLARE @Date1 DATETIME
DECLARE @Date2 DATETIME
DECLARE @type VARCHAR(20)
SET @Date1 = '2010-1-1'
SET @Date2 = '2010-2-1'
SET @type = '{?DateType}'

select *
from filled
WHERE   
    (CASE WHEN @type = 'create' THEN 
    filled.CREATEDON >= @Date1
    AND filled.CREATEDON < DATEADD(d, +1, @Date2)
    WHEN @type <> 'create' THEN   
    filled.datefilled >= @Date1
     AND filled.datefilled < DATEADD(d, +1, @Date2) 
     END)

2 个答案:

答案 0 :(得分:13)

您不需要case声明

WHERE ( (@type = 'create' and filled.CREATEDON >= @Date1 AND filled.CREATEDON < DATEADD(d, +1, @Date2) ) or
        (@type <> 'create' and filled.datefilled >= @Date1 AND filled.datefilled < DATEADD(d, +1, @Date2) ) 
      )

这留下了case语句中的非语义逻辑。这两个条件对@type具有相同的值。我认为这是一个错字。

答案 1 :(得分:8)

在where子句中使用CASE表达式是可能的,但通常可以避免,并使用AND/OR重写,在您的情况下,它将是:

WHERE(  @Type = 'create' 
    AND filled.CREATEDON >= @Date1 
    AND filled.CREATEDON < DATEADD(d, +1, @Date2)
    )
OR  (   @Type != 'create' 
    AND filled.datefilled >= @Date1
    AND filled.datefilled < DATEADD(d, +1, @Date2) 
    )

HOWEVER 这样的查询通常会产生欠佳的计划。如果可能,您应该使用IF/ELSE逻辑:

IF @Type = 'create'
BEGIN
    SELECT  *
    FROM    Filled
    WHERE   Filled.CreatedOn >= @Date1
    AND     Filled.CreatedOn < DATEADD(DAY, 1, @Date2)
END
ELSE
BEGIN
    SELECT  *
    FROM    Filled
    WHERE   Filled.DateFilled >= @Date1
    AND     Filled.DateFilled < DATEADD(DAY, 1, @Date2)
END

原因是@type的值在编译时是未知的,因此优化器不知道它是否需要搜索DateFilledCreatedOn,因此无法使用列中的索引(如果存在),因此无论可用索引如何,都将执行表扫描。然而,如果将逻辑与IF/ELSE分开并且@type的值是什么并不重要,则为IF的每个分支创建一个计划,并且在每个分支中,优化器知道哪个列将是搜索,并可以计划使用适当的索引。

您还可以使用UNION ALL

SELECT  *
FROM    Filled
WHERE   Filled.CreatedOn >= @Date1
AND     Filled.CreatedOn < DATEADD(DAY, 1, @Date2)
AND     @Type = 'create'
UNION ALL
SELECT  *
FROM    Filled
WHERE   Filled.DateFilled >= @Date1
AND     Filled.DateFilled < DATEADD(DAY, 1, @Date2)
AND     @Type <> 'create';

同样,如果DateFilledCreatedOn上存在索引,则生成使用它们的计划的可能性要大于使用OR的计划。