【问题标题】:How do I control the datatype of a computed column?如何控制计算列的数据类型?
【发布时间】:2015-01-08 02:43:47
【问题描述】:

使用 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)] 处的计算域,其中有六个尾随零。

想法?

【问题讨论】:

    标签: sql-server tsql precision sqldatatypes


    【解决方案1】:

    修复

    这就是你想要的:

    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

    这里的数据类型是:

    • 十进制(28, 12)
    • 十进制(38, 3)

    这应该会导致:

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

    但是 DECIMAL 类型的最大长度是 38。那么给出了什么?我们现在需要注意的是,“结果量表”计算附加了一个脚注,即:

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

    所以看来,为了让 Precision 回到 38,它砍掉了 9 个小数位。

    这就是我提出的修复方法有效的原因。我将“Scale”值保持不变,因为我们不想截断进入并且扩展它们没有任何作用,因为 SQL Server 将根据需要扩展 Scale。关键在于降低精度,以便不存在截断或至少最小化。

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

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

    40 超出了限制,因此减少 2 以降低到 38,这意味着将比例减少 2 使我们真正的“结果比例”为 13,这比我们需要的多 1,甚至会看到。

    【讨论】:

    • 感谢您的回答。我担心浮点数精确到小数点后 12 位。您对此有何看法?
    • @jermny :我对此也有一点犹豫,但到目前为止,这是我能找到的扩展有效数字范围的唯一方法。我仍在尝试其他想法,但我想我会先分享这个。但我不确定需要多少关注,因为 FLOAT 通常是准确的,理论上是不精确的,但我认为这应该在规模的远端。
    • @jermny :我想通了,并在不久前发布了答案,现在已经更新了完整的解释。
    • 这是一篇绝对精彩的帖子。非常感谢!
    【解决方案2】:

    使用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 的底部进行了解释。

    【讨论】:

    • 我已经提到我已经尝试过了,但我得到的只是尾随零。另外,我希望它不是 12、6,而是 28、12。
    • @jermny 。 . .你有尾随数字,因为你有 12 的规模。 “精度”是总位数。 “刻度”是小数点右侧的数字。 (msdn.microsoft.com/en-us/library/ms190476.aspx.) 也许你没有使用正确的类型。
    • 感谢您提供有关术语的信息。我很抱歉。
    • 不幸的是,这仍然不起作用:当我执行 ALTER TABLE [xyz].MyTable ADD Mv as cast((OutstandingShares * Price) as decimal(28, 12)) 它仍然有结果3510.88(股)* 5304.987781883689(价格)= 18625175.503660000000(尾随零)。
    • 我想要 12 位小数。我需要能够表示数字 123,456,789,012.123456789012。
    猜你喜欢
    • 2022-11-18
    • 2012-09-15
    • 1970-01-01
    • 2017-08-17
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 2020-10-31
    • 2011-11-06
    相关资源
    最近更新 更多