与以前的 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 以及大多数其他语言中并不精确,因此就标准而言,您看到的细微变化是合法的。如果您想要精确存储,请使用NUMERIC
或DECIMAL
。来自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 server2012加载以前的原有数据库的时候出现了附加错误,怎么办
在某些情况下,为什么CTE(公用表表达式)与SQL Server中的临时表相比会减慢查询速度