CASE表达式在处理前是否评估所有案例?

use*_*871 5 sql sql-server sql-server-2008

我有以下查询:

SELECT
CASE 
    WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', 1, CHARINDEX(' ', 'Sara') - 1)
    ELSE 'Sara'
END AS FirstName,
CASE 
    WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', CHARINDEX(' ', 'Sara') + 1, 8000)
    ELSE ''
END AS LastName
Run Code Online (Sandbox Code Playgroud)

非常简单 - 我正在测试名称拆分查询.所以我测试名称没有空格的场景,我得到以下异常:

传递给SUBSTRING函数的长度参数无效.

这是为什么?如果评估第一个条款并立即进入ELSE?我该怎么解决这个问题?

Y.B*_*.B. 11

优化器足够聪明,可以注意到你在那里有持续表达并尝试评估它.将常量传递给变量会欺骗它运行:

DECLARE @TestString nvarchar(100) = 'Sara';

SELECT
    CASE 
        WHEN @TestString like '% %'
        THEN SUBSTRING(@TestString, 1, CHARINDEX(' ', @TestString) - 1)
        ELSE @TestString
    END AS FirstName,
    CASE 
        WHEN @TestString like '% %'
        THEN SUBSTRING(@TestString, CHARINDEX(' ', @TestString) + 1, 8000)
        ELSE ''
    END AS LastName
Run Code Online (Sandbox Code Playgroud)

要回答这个问题,处理器THEN只有在WHEN时才计算表达式,否则只计算ELSE表达式.但即便在此之前,Optimizer会尝试用计算值替换所有常量表达式,以便Processor不必为每一行重新计算它们.它被称为" 恒定折叠 ".

  • 它试图用计算值替换表达式,以便处理器不必为每一行重新计算它. (2认同)

Ric*_*ner 7

使用变量工作;

DECLARE @NameString varchar(10); SET @NameString = 'Sara'

SELECT
CASE 
    WHEN @NameString like '% %' THEN SUBSTRING(@NameString, 1, CHARINDEX(' ', @NameString) - 1)
    ELSE @NameString
END AS FirstName,
CASE 
    WHEN @NameString like '% %' THEN SUBSTRING(@NameString, CHARINDEX(' ', @NameString) + 1, 8000)
    ELSE ''
END AS LastName
Run Code Online (Sandbox Code Playgroud)

代码的问题在于它会在传递静态值时检查每个部分是否有效.它不喜欢CHARINDEX(' ', 'Sara') - 1解析为-1.解决这个问题的方法是将此函数包装在ABS()函数中;

SELECT
CASE 
    WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', 1, ABS(CHARINDEX(' ', 'Sara') - 1))
    ELSE 'Sara'
END AS FirstName,
CASE 
    WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', CHARINDEX(' ', 'Sara') + 1, 8000)
    ELSE ''
END AS LastName
Run Code Online (Sandbox Code Playgroud)