SQL Server 2005 数值精度损失

SQL server 2005 numeric precision loss

提问人:Ilya Komakhin 提问时间:9/24/2008 最后编辑:MrValdezIlya Komakhin 更新时间:6/4/2013 访问量:9250

问:

调试一些与金融相关的 SQL 代码时,发现 numeric(24,8) 数学精度存在一个奇怪的问题。

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

选择 A, B, C, A + B * C 从 ( 选择 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 ) 吨

因此,我们丢失了 2 个重要符号。试图以不同的方式解决这个问题,我得到了中间乘法结果(即零!)到数字(24,8)的转换会很好。

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

sql-server 浮点类型 转换 转换 浮点精度

评论


答:

7赞 Eugene Yokota 9/24/2008 #1

正如浮点型的相加不准确一样,如果超过精度,十进制类型的乘法也可能不准确(或导致不准确)。请参阅数据类型转换十进制和数字

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

因此,原始查询

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

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

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

四舍五入后给你。0.123457

评论

0赞 Edmondo 12/4/2012
你的意思是 NUMERIC(32,6)) 吗?如果总和必须为 38
0赞 Eugene Yokota 12/4/2012
@Edmondo1984 请阅读链接并理解这两个数字的含义。
0赞 Edmondo 12/4/2012
你说当将两个数字 (24,8) 相乘时,服务器将尝试保存 16 位并产生 (32,6) ,它是如何变成 38,6 的?谢谢
1赞 Eugene Yokota 12/5/2012
@Edmondo1984 In ,代表位数的精度。所以里面有 16 位非小数位数字。没有位。同样,请阅读 msdn 文档的链接。NUMERIC(p, s)pNUMERIC(24, 8)
0赞 kristof 9/24/2008 #2

按照 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

评论

0赞 Eugene Yokota 9/24/2008
这种方法可能无法解决 SQL Server 砍掉小数部分的问题。为了保存小数部分,可能需要转换为 @a 并@b为 double。
0赞 kristof 9/25/2008
谢谢,在SQL中处理一些精确数学时,我会牢记它,到目前为止,我不需要使用它,但现在可能有一些问题需要考虑,这很好
0赞 phoenix10k 6/4/2013 #3

尽管它对精度、小数位数和长度 (Transact-SQL) 进行了说明。我相信它还将 6 的最小“比例”(小数位数)应用于生成的 NUMERIC 类型进行乘法,就像它对除法等所做的那样。