如何控制计算列的数据类型?

时间:2014-11-11 14:09:08

标签: sql-server tsql precision sqldatatypes

使用SQL Server 2012 ...

我有两列:

Price [decimal(28,12)]
OustandingShares [decimal(38,3)] -- The 38 is overkill but alas, not my call.

当我执行ALTER TABLE时,我得到一个结果计算列为[decimal(38,6)]。我需要数据类型为[decimal(28,12)]。

ALTER TABLE [xyz].MyTable
ADD Mv AS OustandingShares * Price

如何在此计算列上有效获得12位小数?我尝试将OutstandingShares转换为12位小数,并围绕OutstandingShares * Price包装转换。我得到的唯一一个是[decimal(28,12)]的计算字段,有六个尾随零。

思想?

2 个答案:

答案 0 :(得分:3)

修复

这样做你想要的:

CONVERT(DECIMAL(28,12), (
                            CONVERT(DECIMAL(15, 3), [OustandingShares])
                          * CONVERT(DECIMAL(24, 12), [Price])
                         )
       )

用此测试:

SELECT CONVERT(DECIMAL(28,12),
                 (CONVERT(DECIMAL(24,12), 5304.987781883689)
               * CONVERT(DECIMAL(15,3), 3510.88)));

结果:

  

18625175.503659806036

原因

由于SQL Server关于如何在各种操作中处理精度和比例的规则,计算被截断。这些规则在Precision, Scale, and Length的MSDN页面中有详细说明。我们对这个案例感兴趣的细节是:

  • 操作: e1 * e2
  • 结果精确度: p1 + p2 + 1
  • 结果比例*: s1 + s2

这里的数据类型是:

  • DECIMAL(28,12)
  • DECIMAL(38,3)

这应该导致:

  • 精度=(28 + 38 + 1)= 67
  • 比例= 15

但是DECIMAL类型的最大长度是38.那么是什么给出了?我们现在需要注意的是,"结果标尺附有一个脚注"计算,是:

  

*结果精度和标度的绝对最大值为38.当结果精度大于38时,相应的标度会减小,以防止结果的整数部分被截断。

所以看起来为了让精确度回落到38,它会砍掉9位小数。

这就是我提出的解决方案有效的原因。我保留了" Scale"值与我们不希望截断进入并且扩展它们没有任何意义相同,因为SQL Server将根据需要扩展Scale。关键在于降低精度,以便截断不存在或至少是最小的。

使用DECIMAL(15, 3)DECIMAL(24, 12)我们应该得到:

  • 精度=(15 + 24 + 1)= 40
  • 比例= 15

40超过限制因此减少2以降低到38,这意味着将比例缩小2,使我们得到真实的"结果比例" 13,这比我们需要的还要多,甚至会看到。

答案 1 :(得分:0)

使用cast()convert()。类似的东西:

ALTER TABLE [xyz].MyTable ADD Mv AS cast(OustandingShares * Price as decimal(12, 6)

或您想要的任何类型。

编辑:

哦,我想我已经明白了。问题在于计算本身。在这种情况下,在乘法之前进行转换,这样您就不必依赖SQL Server的(奥术)规则来符合小数类型。

ALTER TABLE [xyz].MyTable
    ADD Mv AS cast(OustandingShares as decimal(28, 12) * cast(Price as decimal(28, 12))

我相信在您的情况下发生的事情是计算结果的最大精度超过了允许的阈值,因此相应地减小了比例。这在page的底部进行了解释。