SQL Server有意思的数据类型隐式转换问题

Posted kerrycode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server有意思的数据类型隐式转换问题相关的知识,希望对你有一定的参考价值。

写这篇文章的时候,还真不知道如何取名,也不知道这个该如何将其归类。这个是同事遇到的一个案例,案例比较复杂,这里抽丝剥茧,仅仅构造一个简单的案例来展现一下这个问题。我们先构造测试数据,如下所示:

 

CREATE TABLE TEST
( 
  ID    INT, 
  GOOD_TYPE  VARCHAR(12),
  GOOD_WEIGHT NUMERIC(18,2)
)
 
INSERT INTO dbo.TEST
VALUES( 1, ‘T1‘,1.27) 

 

SELECT  GOOD_TYPE,
        CASE WHEN ( GOOD_TYPE = ‘T1‘ ) THEN 99.1 + SUM(GOOD_WEIGHT)
             ELSE CEILING(SUM(GOOD_WEIGHT))
        END AS GrossWeight ,
        SUM(GOOD_WEIGHT) AS NetWeight
FROM    dbo.TEST
GROUP BY GOOD_TYPE;

 

 

技术图片

 

如上所示,为什么99.1 + SUM(GOOD_WEIGHT)变成100了呢? 原始SQL非常复杂,我们分析、排除掉各个因素后,始终不得要领,各种折腾中发现,如果这样转换一下(请见下面截图),居然就OK了,后面分析了一下,应该是CASE WHEN里面的不同数据类型导致隐式转换,说实话之前还真没有留意CASE WHEN中存在数据类型的隐性转换,但是为什么就一定从NUMERIC转换为INT了呢? 而不是INT隐性转换为NUMERIC呢, 说实话没有看到相关文档的官方,如果按照官方文档:

 

当两个不同数据类型的表达式用运算符组合后,优先级较低的数据类型首先转换为优先级较高的数据类型。 如果此转换不是所支持的隐式转换,则返回错误。 对于组合具有相同数据类型的操作数表达式的运算符时,运算的结果便为该数据类型

 

而我们知道,Decimal 和 NUMERIC 是同义词,可互换使用,而官方文档数据类型优先级 (Transact-SQL)”中,Decimal的优先级明显高于INT,如果真要按照原理来解释,应该是INT转换NUMERIC才对(两种数据类型支持隐式转换),所以越想越糊涂,只知道有这么一回事,但是真正的Root Cause尚不清楚,而且在精确度要求较高的报表中,这种现象就会类似Bug一样的突然出现。需要谨慎留心!

 

技术图片

 

参考资料:

 

https://docs.microsoft.com/zh-cn/sql/t-sql/data-types/data-type-precedence-transact-sql?view=sql-server-2017

https://docs.microsoft.com/zh-cn/sql/t-sql/data-types/data-type-conversion-database-engine?view=sql-server-2017

以上是关于SQL Server有意思的数据类型隐式转换问题的主要内容,如果未能解决你的问题,请参考以下文章

也谈SQL Server 2008 处理隐式数据类型转换在运行计划中的增强 (续)

也谈SQL Server 2008 处理隐式数据类型转换在运行计划中的增强

Spring JDBC for SQL Server - 使用 SQLXML 数据类型产生 SQLServerException:不允许从数据类型 xml 到 nvarchar(max) 的隐式转换

SQL SERVER中隐式转换的一些细节浅析

SQL SERVER中隐式转换的一些细节浅析

见识一下SQL Server隐式转换处理的不同