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

Jua*_*lez 53 sql-server t-sql case

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

SELECT
    CASE
        WHEN 1+1 = 2 THEN'YES'
        WHEN 1+1 = 3 THEN 'NO'
        WHEN 1+1 = 2 THEN 'NO' 
    END
Run Code Online (Sandbox Code Playgroud)

结果是“YES”,即使最后一个 when 条件应该使它评估为“NO”。一旦找到第一个 TRUE 条件,它似乎就退出了。有人可以确认是否是这种情况

Jam*_*ins 54

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

参考 https://docs.microsoft.com/sql/t-sql/language-elements/case-transact-sql


这是标准的 SQL 行为:

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

  • 如果不存在真条件,则对ELSE零件求值。

  • 如果没有真条件也没有ELSE部分,则计算结果为NULL

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

Lei*_*fel 16

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;  
Run Code Online (Sandbox Code Playgroud)

但是,从 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;
Run Code Online (Sandbox Code Playgroud)

同样的测试不能用 MySQL 完成,因为它返回 NULL 以除以零。( SQL 小提琴)

  • 是的,我同意“通常”。正如 Aaron 在他的回答中指出的那样,一项测试足以反驳“CASE 总是短路”的说法。但通常是这样。 (3认同)
  • 小提琴 ** 是关于 SQL-Server **。这是 Aaron 的回答:[即使第一个参数不为 NULL,SQL Server 是否会读取所有 COALESCE 函数?](http://dba.stackexchange.com/questions/12941/does-sql-server-read-all-一个合并函数,即使第一个参数是否) (2认同)

Ken*_*her 8

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
Run Code Online (Sandbox Code Playgroud)