【问题标题】:SQL server 2005 numeric precision lossSQL Server 2005 数值精度损失
【发布时间】:2008-09-24 10:31:37
【问题描述】:

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

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

选择 A, 乙, C, A + B * C 从 ( 选择 CAST(0.12345678 作为数字(24,8))作为 A, CAST(0 作为数字(24,8))作为 B, 铸造(500 作为数字(24,8))作为 C ) T

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

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

【问题讨论】:

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


    【解决方案1】:

    就像浮点类型的加法不准确一样,如果超过精度,十进制类型的乘法可能不准确(或导致不准确)。请参阅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

    【讨论】:

    • 你的意思是 NUMERIC(32,6)) 吗?如果总和必须是 38
    • @Edmondo1984 请阅读链接并理解这两个数字的含义。
    • 你说两个数字(24,8)相乘时服务器会尝试保存16位并产生一个(32,6),它怎么变成38,6?谢谢
    • @Edmondo1984 在NUMERIC(p, s) 中,p 代表精确度 total 位数。所以NUMERIC(24, 8) 中有 16 位非小数。没有位。请再次阅读 msdn 文档的链接。
    【解决方案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
    

    【讨论】:

    • 这种方法可能无法解决 SQL Server 截断小数部分的问题。要保存小数部分,可能需要将 @a 和 @b 转换为 double。
    • 谢谢,在 SQL 中处理一些精确数学时我会牢记这一点,到目前为止我还不需要使用它,但现在可能有一些问题需要考虑,这很好跨度>
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2014-05-12
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 2014-07-13
      • 1970-01-01
      • 1970-01-01
      • 2014-09-24
      • 2020-07-28
      相关资源
      最近更新 更多