5

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

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

选择 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)) 作为 C) T

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

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

4

3 回答 3

7

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

NUMERIC(24,8)由于您将and相乘NUMERIC(24,8),并且 SQL Server 只会检查类型而不是内容,因此当它无法保存所有 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四舍五入后给你。

于 2008-09-24T10:54:31.947 回答
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
于 2008-09-24T12:02:14.873 回答
0

尽管它在Precision、Scale 和 Length (Transact-SQL)上说了什么。我相信它也会将 6 的最小“比例”(小数位数)应用于结果 NUMERIC 类型的乘法,就像它对除法等所做的一样。

于 2013-06-04T09:43:21.743 回答