SQL server 2005数值精度损失

时间:2008-09-24 10:31:38

标签: sql-server floating-point type-conversion casting floating-accuracy

调试一些与财务相关的SQL代码,发现了一个数学(24,8)数学精度的奇怪问题。

在MSSQL上运行以下查询,您将获得A + B * C表达式结果为0.123457

选择A,        B,        C,        A + B * C. 从 ( SELECT CAST(0.12345678 AS NUMERIC(24,8))AS A,        CAST(0 AS NUMERIC(24,8))AS B,        CAST(500 AS NUMERIC(24,8))AS C )T

所以我们丢失了2个重要符号。试图以不同的方式解决这个问题,我将中间乘法结果(即Zero!)转换为数字(24,8),这样可以正常工作。

最后有一个解决方案。但我还有一个问题 - 为什么MSSQL会以这种方式运行,以及我的样本中实际发生了哪种类型的转换?

3 个答案:

答案 0 :(得分:7)

正如浮点类型的添加不准确一样,如果超出精度,则十进制类型的乘法可能不准确(或导致不准确)。请参阅Data Type Conversiondecimal and numeric

由于您将NUMERIC(24,8)NUMERIC(24,8)相乘,而SQL Server只检查类型而非内容,它可能会尝试保存潜在的16位非十进制数字(24 - 8)无法保存所有48位数的精度(最大值为38)。结合其中两个,你得到32个非十进制数字,只留下6位十进制数字(38 - 32)。

因此原始查询

SELECT A, B, C, A + B * C
FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A,
  CAST(0 AS NUMERIC(24,8)) AS B,
  CAST(500 AS NUMERIC(24,8)) AS C ) T

缩减为

SELECT A, B, C, A + D
FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A,
  CAST(0 AS NUMERIC(24,8)) AS B,
  CAST(500 AS NUMERIC(24,8)) AS C,
  CAST(0 AS NUMERIC(38,6)) AS D ) T

同样,在NUMERIC(24,8)NUMERIC(38,6)之间,SQL Server将尝试保存潜在的32位非小数,因此A + D缩减为

SELECT CAST(0.12345678 AS NUMERIC(38,6))

在舍入后为您提供0.123457

答案 1 :(得分:0)

遵循eed3si9n所指出的逻辑以及你在问题中所说的,似乎在进行数学运算时最好的方法是将它们提取到函数中,并在每次运算后指定精度,

在这种情况下,该功能可能类似于:

create function dbo.myMath(@a as numeric(24,8), @b as numeric(24,8), @c as numeric(24,8))
returns  numeric(24,8)
as
begin 
    declare @d as numeric(24,8)
    set @d = @b* @c
    return @a + @d
end

答案 2 :(得分:0)

尽管它在Precision, Scale, and Length (Transact-SQL)上说了什么。我相信它也会将最小的“比例”(小数位数)6应用于生成的NUMERIC类型,以便进行乘法运算,与分割等相同。