SQL Server CASE语句是否评估所有条件或在第一个TRUE条件下退出?


44

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

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

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


5
密切相关:即使第一个参数不为NULL,SQL Server也会读取所有COALESCE函数吗?(正如COALESCE()翻译成CASE表达式一样。)
ypercubeᵀᴹ2013年

Answers:


46

•返回评估为TRUE第一个 input_expression = when_expression 的result_expression 。

参考 http://msdn.microsoft.com/en-us/library/ms181765.aspx


这是标准的SQL行为:

  • CASE表达式计算为第一真条件。

  • 如果没有真实条件,它将评估ELSE零件。

  • 如果没有真实条件,也没有ELSE分量,则结果为NULL


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

15

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-小提琴
ypercubeᵀᴹ


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

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

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

7

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

在以下测试中,我有3个测试。第一个始终为真,第二个始终不引用表而失败,而第三个仅在考虑了数据后才会失败。
在此特定运行中,成功返回了两行。如果我注释掉第一个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

1

如果WHERE条件中使用的case语句和when语句中的第一个case语句涉及评估表中的列值,并且表中的第一行不满足此条件,则case语句将转到下一个case when语句。

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

1

在MySQL中,它将在第一个true选项上退出case语句。如果您可能有多个真值,则可以在序列中的较早位置放置首选答案。


问题是关于SQL Server。
詹姆斯·安德森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.