【问题标题】:Sql Server Decimal(30,10) losing last 2 decimalsSql Server Decimal(30,10) 丢失最后 2 位小数
【发布时间】:2009-09-21 16:54:29
【问题描述】:

在 Sql Server 05 中除以 2 个小数 (30,10) 时,最后 2 个小数似乎丢失了(甚至没有四舍五入,只是被截断)。

例如:

Declare @x decimal(30,10)
Declare @y decimal(30,10)
Declare @z decimal(30,10)

select @x = 2.1277164747 
select @y = 4.8553794574

Select @z = @y/@x   
select @z 

结果:2.2819673100

但是如果将 2 个被除的数字转换为似乎可以工作的浮点数:

....
Select @z = cast(@y as float)/cast(@x as float)
select @z 

结果:2.2819673181

为什么 Sql 会这样做?在 Sql 中,什么是在不损失精度的情况下划分小数的正确方法。

【问题讨论】:

  • 好问题。更奇怪的是,将声明更改为 (38 ,10) 实际上会使它更糟,而实际上将它们更改为 (20,10)似乎修复它。没有意义...

标签: sql sql-server tsql


【解决方案1】:

SQL Server 中允许的最大精度为 38。您使用的是 Decimal(30,10)。最大值为 99,999,999,999,999,999,999.9999999999 如果将此数字除以 0.000000001,最终将得到更大的数字,因此生成的数据类型必须能够容纳它。这会导致您失去一些精度。

将您的原始数据类型更改为 Decimal(20,10) 并且不会发生此问题。

有关数据类型的完整规则(以及它们如何受数学运算影响):

Full rules here

【讨论】:

  • 这是正确答案。 SQL Server 根据输入 types 而不是输入 values 的精度和比例来确定结果的精度和比例。所以,结果计算为十进制(30,8),然后转换为十进制(30,10)存储在@z中。
  • 这是有道理的,但是>>这会导致你失去一些精度
  • 人们似乎特别想念的一件事是,在对 2 个最高精度数字进行除法时,比例会减少到 6 位。十进制(38,10)/十进制(38,10)=十进制(38,6)。我有一次解释说,他们必须这样做以保护内部工作的精度,以防溢出。
  • @richardtallent,结果精度实际上是十进制(38,8)。将此添加到上面的代码中:选择 SQL_VARIANT_PROPERTY(@y/@x, 'Precision'), SQL_VARIANT_PROPERTY(@y/@x, 'Scale')
  • 大约一年前我在博客上写过这个:blogs.lessthandot.com/index.php/DataMgmt/DataDesign/…
【解决方案2】:

简而言之,使用强制转换来保证您的结果。当您将 @x 和 @y 分配给文字值时,它们可能会采用这些文字的精度。这有助于解释为什么按这些值进行划分没有达到您的预期。

【讨论】:

  • 如果你运行 SELECT @x,@y 你会看到 @x 和 @y 包含所有的十进制数字
  • @x 和@y 的字面值被正确存储,被截断的是存储在@z 中的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
相关资源
最近更新 更多