与以前的 SQL Server 版本相比,ROUND 函数返回不同的结果 SQL Server 2016

Posted

技术标签:

【中文标题】与以前的 SQL Server 版本相比,ROUND 函数返回不同的结果 SQL Server 2016【英文标题】:ROUND function returns different results SQL Server 2016 compared to prior SQL Server versions 【发布时间】:2018-04-10 05:21:20 【问题描述】:

对具有 SQL Server 2008、SQL 2012、SQL 2014 和 SQL Server 2016 兼容模式的数据库执行以下语句。

SQL Server 2008、SQL Server 2012 和 SQL Server 2014 返回的结果相同,除了 SQL Server 2016。

SQL语句:

DECLARE @VarFloat FLOAT    
SET @VarFloat = 1.90255    

SELECT ROUND(@VarFloat, 4) Variable_Float, ROUND(1.90255, 4) Input_Float

在 SQL Server 2008 / 2012 / 2014 上执行时的结果:

Variable_Float         Input_Float
---------------------- -----------
1.9026                 1.90260

在 SQL Server 2016 上执行时的结果:

Variable_Float         Input_Float
---------------------- ------------
1.9025                 1.90260

SQL Server 2016 舍入不同于以前的版本,似乎已经向下舍入了该值。有没有人遇到过类似的问题?

谢谢!

【问题讨论】:

这在 SQL 中可能是允许的,但这看起来要么是一个非常激进和奇怪的性能优化,要么是一个无意的错误。请注意,如果 VarFloat 设置为 1.9025500000000001,它会向上取整,因此 var 不会被截断为 32 位或类似的值。 【参考方案1】:

浮点运算在 SQL Server 以及大多数其他语言中并不精确,因此就标准而言,您看到的细微变化是合法的。如果您想要精确存储,请使用NUMERICDECIMAL。来自documentation:

请注意,十进制和数字数据类型彼此完全等价。这两种数据类型都保留在产品中以实现向后兼容性。当您需要存储带小数位的精确数字数据时,可以使用任何一种数据类型

【讨论】:

【参考方案2】:

实际上,SQL Server 2016 的舍入方式与其他所有版本并没有什么不同,这可能只是与这个数字的巧合。如果您要选择另一个版本,则版本可能根本不对齐。

这里发生的事情是为什么float 是在 SQL Server 中使用的“危险”格式的经典示例。据官方documentation:

用于浮点数值的近似数数据类型 数据。浮点数据是近似的;因此,并非所有值 数据类型范围可以精确表示。 ISO 的同义词 real 是 float(24)。

如果您想获得带小数位的精确数据,您应该使用 SQL Server decimal data type。

【讨论】:

以上是关于与以前的 SQL Server 版本相比,ROUND 函数返回不同的结果 SQL Server 2016的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 内存优化表 - 与临时表相比性能较差

SQL Server两种分页性能比较

sql server2012加载以前的原有数据库的时候出现了附加错误,怎么办

在某些情况下,为什么CTE(公用表表达式)与SQL Server中的临时表相比会减慢查询速度

SQL Server "<>" 运算符与具有几百万行的表上的 "=" 相比非常慢

%ROWTYPE相当于在SQL Server