SQL Server中ISNUMERIC()参数校验是否先于CASE WHEN逻辑执行?
先看第一个示例,这个CASE表达式能正常返回1,符合WHEN子句按顺序匹配、匹配成功后短路后续逻辑的预期:
SELECT CASE WHEN 1=1 THEN 1 WHEN 1=1 THEN 1/0 END
这里第二个WHEN的1/0不会被执行,因为第一个WHEN已经匹配成功。
但第二个示例却报错:
DECLARE @VAR DATETIME2 SELECT CASE WHEN 1=1 THEN 1 WHEN 1=0 THEN ISNUMERIC(@VAR) END
错误信息:
Msg 8116, Level 16, State 1, Line 9
Argument data type datetime2 is invalid for argument 1 of isnumeric function.
明明第二个WHEN的条件1=0永远为假,为什么还会触发这个错误?
原因分析
这不是执行阶段的问题,而是编译阶段的类型验证导致的。SQL Server在编译查询时,会检查所有表达式的类型合法性,不管它们是否会在执行阶段被实际执行。
ISNUMERIC()函数要求参数是数值类型或可隐式转换为数值的类型,而datetime2类型无法隐式转换为数值类型,所以编译器在检查到ISNUMERIC(@VAR)这个表达式时,直接判定参数类型不合法,抛出错误,根本不会进入执行阶段去判断WHEN条件是否满足。
第一个示例里的1/0是运行时错误(除零),编译器不会在编译阶段检查这种运行时逻辑错误,只会在执行阶段当这个表达式被触发时才会报错;而第二个示例的错误是编译时的类型错误,属于语法/类型合法性问题,编译器会提前拦截。
解决方法
如果需要避免这种编译错误,可以通过强制类型转换确保参数类型合法,比如:
DECLARE @VAR DATETIME2 SELECT CASE WHEN 1=1 THEN 1 WHEN 1=0 THEN ISNUMERIC(CAST(@VAR AS VARCHAR(30))) END
这里把datetime2转换为字符串后再传入ISNUMERIC(),编译器就会认可参数类型的合法性,而由于第二个WHEN条件永远不满足,这个转换和函数调用也不会实际执行。
内容的提问来源于stack exchange,提问作者gebruiker

