我有以下查询:
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
?我该如何解决这个问题??
答案 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