SQL Server(特别是2008或2012年)CASE语句是否评估所有WHEN条件,或者找到找到评估为true的WHEN子句后退出?如果它确实经历了整个条件集,是否意味着最后一个评估为true的条件会覆盖第一个评估为true的条件?例如:

SELECT
    CASE
        WHEN 1+1 = 2 THEN'YES'
        WHEN 1+1 = 3 THEN 'NO'
        WHEN 1+1 = 2 THEN 'NO' 
    END


即使最后一个条件将其评估为“否”,结果仍为“是”。一旦找到第一个TRUE条件,它似乎就会退出。有人可以确认是否是这种情况吗。

评论

密切相关:即使第一个参数不为NULL,SQL Server也会读取所有COALESCE函数吗? (因为COALESCE()转换为CASE表达式。)

#1 楼

•返回结果为TRUE的第一个input_expression = when_expression的result_expression。

参考
http://msdn.microsoft.com/zh-cn/library/ms181765.aspx


这是标准的SQL行为:


CASE表达式的计算结果为第一个真实条件。
如果没有真实条件,则求和为ELSE部分。
如果没有真实条件,没有ELSE零件,则求值为NULL


评论


我只是想确保如果我有3个条件条件都可以评估为true的情况,我只希望执行第一个条件评估为true的任务,而不要执行其他两个任务条件(即使它们也评估为true) )。从我的问题中的示例查询来看,情况确实如此。我只是想确认一下。我也希望SQL从上到下读取CASE条件。谢谢!

– Juan Velez
13年5月30日在13:42



#2 楼

SQL Server通常会对CASE语句(SQLFiddle)进行短路评估:

--Does not fail on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 1 THEN 'Case 1'
      WHEN 2/0 = 1 THEN 'Case 2'
   END;

--Fails on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 99 THEN 'Case 1'
      WHEN 2/0 = 99 THEN 'Case 2'
   END;  


但是,从SQL Server 2012开始,有几种类型的语句不能正确地短路-电路。请参阅注释中ypercube的链接。

Oracle始终进行短路评估。请参见《 11.2 SQL语言参考》。或比较以下(SQLFiddle):

--Does not fail on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 1 THEN 'Case 1'
    WHEN 2/0 = 1 THEN 'Case 2'
  END
FROM dual;


--Fails on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 99 THEN 'Case 1'
    WHEN 2/0 = 99 THEN 'Case 2'
  END
FROM dual;


用MySQL无法完成此测试,因为它返回NULL以除以零。 (SQL小提琴)

评论


怎么样?:SQL-Fiddle

–超立方体ᵀᴹ
13年5月30日在13:24

小提琴是关于SQL-Server的。这是亚伦的答案:即使第一个参数不为NULL,SQL Server也会读取所有COALESCE函数吗?

–超立方体ᵀᴹ
13年5月30日在13:39



@ypercube这是非常有趣的行为。它正在评估将在else部分中运行的代码,但似乎会忽略它,这取决于存在其他WHEN表达式以及除零是否在MIN内。参见sqlfiddle.com/#!6/d41d8/4468

–雷·里菲尔(Leigh Riffel)
13年5月30日在13:52

@ypercube现在,我已经阅读了您发布的一些链接,您是否会说有足够多的案例说明SQL Server是否进行短路评估的答案通常是-?

–雷·里菲尔(Leigh Riffel)
13年5月30日在13:58



是的,我同意“通常”。正如亚伦(Aaron)指出的那样,一项测试足以证明“案例总是短路”。但是通常是这样。

–超立方体ᵀᴹ
2013年5月30日14:19



#3 楼

看来MS SQL Server也使用短路评估。

在以下测试中,我有3个测试。第一个始终为true,第二个始终不引用表而失败,而第三个仅当考虑到数据时失败。
在此特定运行中,两行都成功返回。如果我注释掉第一个WHEN,或者第一个和第二个,那么我会失败。

CREATE TABLE casetest (test varchar(10))
GO
INSERT INTO casetest VALUES ('12345'),('abcdef')
GO

SELECT CASE WHEN LEN(test)>1 THEN test
        WHEN 1/0 = 1 THEN 'abc'
        WHEN CAST(test AS int) = 1 THEN 'def'
        END
FROM casetest
GO


#4 楼

在MySQL中,它将在第一个true选项上退出case语句。如果您可能有多个真值,则希望在顺序的前面放置首选答案。

评论


问题是关于SQL Server。

–詹姆斯·安德森(James Anderson)
17年4月15日在8:26

#5 楼

如果在WHERE条件中使用的case语句以及when语句的第一个case涉及评估表中的列值,并且表中的第一行不满足此条件,则case语句将在when语句时转到下一个case。 >
declare @tbl table(id int)
insert into @tbl values(1)
insert into @tbl values(2)
insert into @tbl values(3)

--Fails on the divide by zero.
SELECT * FROM @tbl
where  CASE 
        WHEN id = 2 THEN 1 -- first row in table will not satisfy the condition
        WHEN 2/0 = 1 THEN 1
        ELSE 0
      END =1

-- when filter the records to only who will staisfy the first case when condition, it 
will not fail on the divide by zero
SELECT * FROM @tbl
where ID=2 and -- first row in table will  satisfy the condition
  CASE 
    WHEN id = 2 THEN 1
    WHEN 2/0 = 1 THEN 1
    ELSE 0
  END =1