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

时间:2016-07-06 13:51:11

标签: 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

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

  

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

为什么?是否评估第一个条款并立即转到ELSE?我该如何解决这个问题??

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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

您的代码的问题在于它会在传递静态值时检查每个部分是否有效。它并不像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