为啥 T-SQL ISNULL() 截断字符串而 COALESCE 不截断?
Posted
技术标签:
【中文标题】为啥 T-SQL ISNULL() 截断字符串而 COALESCE 不截断?【英文标题】:Why is T-SQL ISNULL() truncating the string and COALESCE is not?为什么 T-SQL ISNULL() 截断字符串而 COALESCE 不截断? 【发布时间】:2013-09-23 23:33:33 【问题描述】:鉴于以下情况:
SELECT ISNULL('XY' + NULL, 'ABCDEFGHIJ') -- Outputs ABC (Why?)
SELECT COALESCE('XY' + NULL, 'ABCDEFGHIJ') -- Outputs ABCDEFGHIJ
为什么这些语句返回不同的结果?
【问题讨论】:
【参考方案1】:根据微软documentation,功能:
ISNULL(check_expression, replacement_value)
replacement_value
必须是可隐式转换为check_expression
类型的类型。请注意'xy'+NULL
的类型是VARCHAR(3)
。因此,您的字符串 'ABCDEFGHIJ'
被强制转换为 VARCHAR(3)
并因此被修剪。
为什么不是VARCHAR(2)
听起来很奇怪,但事实就是这样——比'xy'
长一个字符。您可以使用这个 SQLFiddle 并亲自查看'xy'+NULL
的类型与表达式CASE WHEN 1=2 THEN 'XYZ' ELSE NULL END
相同,即NULL
但隐式兼容VARCHAR(3)
。
对于表达式'xy'+NULL
,感知长度似乎可以计算为'xy'
字符串长度(2)加上每添加一个NULL
1。例如,'xy'+NULL+NULL
的类型是 VARCHAR(4)
,'xy'+NULL+NULL+NULL
的类型是 VARCHAR(5)
等等 - 看看这个 SQLFiddle。这非常奇怪,但这就是 MS SQL Server 2008 和 2012 的工作方式。
【讨论】:
很好的解释,虽然我不相信 varchar(3) 而不是 varchar(2) - 我在任何地方都找不到它的文档。 我必须增加这里的信息来解释更多关于 COALESCE 行为而不是 ISNULL 行为的信息,来自 Microsoft documentation:COALESCE 表达式是 CASE 表达式的语法快捷方式。也就是说,查询优化器将代码 COALESCE(expression1,...n) 重写为以下 CASE 表达式: CASE WHEN (expression1 IS NOT NULL) THEN expression1 WHEN (expression2 IS NOT NULL) THEN expression2 ... ELSE expressionN END -> case 返回类型由最高的 expr 优先级给出。 这解释了COALESCE
的行为,但没有说明为什么'xy'+NULL
的类型是VARCHAR(3)
。这一定与 SQL Server 内部有关。
我不确定我是否得到了你的样品证明。第二个查询是一个 varchar(3) 因为 'XYZ' 而不是因为 NULL 的 CASE,对吧?所以我猜剩下的疑问是关于 'X'+NULL 变成 varchar(2) 而不是 varchar(1)。那么,在这种情况下,NULL 是否被视为单个字符?使用 ISNULL 连接字符串时是否需要担心溢出/截断?
是的,NULL 增加了 1 个字符。这很奇怪,但这里有确凿的证据:sqlfiddle.com/#!3/d41d8/20994【参考方案2】:
您可以在这里查看所有差异,非常清楚
MSDN:http://msdn.microsoft.com/en-us/library/ms190349.aspx
MSDN 博客:http://blogs.msdn.com/b/sqltips/archive/2008/06/26/differences-between-isnull-and-coalesce.aspx
【讨论】:
+1 为博客文章,我在第一次研究时没有注意到它。很好的资源。【参考方案3】:ISNULL()
将替换值转换为检查表达式的类型。在这种情况下,检查表达式的类型是CHAR(2)
,因此转换替换值会截断它(你确定你得到的是ABC
而不仅仅是AB
?)。
来自微软documentation:
如果
replacement_value
比check_expression
长,replacement_value
可以被截断。
【讨论】:
以上是关于为啥 T-SQL ISNULL() 截断字符串而 COALESCE 不截断?的主要内容,如果未能解决你的问题,请参考以下文章
将 T-SQL ISNULL 函数逻辑复制到 SparkSQL
IsNull、IsEmpty、=Empty 和空字符串(即“”)有啥不同,为啥我可以使用变体