【问题标题】:SQL Server decimal calculation and default valueSQL Server 十进制计算和默认值
【发布时间】:2020-06-17 09:39:07
【问题描述】:

谁能解释以下结果。我读过SQL小数类型以及做乘法和除法时的精度和小数位数,但我仍然无法理解:

select cast(7 as decimal(25,13))*cast(15 as decimal(25,13)) = 105.0000000000000

select cast(15 as decimal(25,13))/cast(11 as decimal(25,13)) = 1.3636363636363

select cast(7 as decimal(25,13))*cast(15 as decimal(25,13))/cast(11 as decimal(25,13)) = 9.545454

select cast(cast(7 as decimal(25,13))*cast(15 as decimal(25,13)) as decimal(25,13))/cast(11 as decimal(25,13)) = 9.5454545454545

所以乘法和除法产生 13 个小数,但是当它们链接起来时,它们突然产生 6 个小数。只有当乘法首先被转换为小数(25,13)然后才被除,它才会再次产生 13 个小数。 SQL Server 是否将乘法转换为默认的小数(38,0),然后除以小数(25,13)?

我正在为非常低价的产品进行 bom 计算,我想要我能得到的所有小数。我是否需要在每一步都进行这种转换,或者如果没有另外说明,我是否可以以某种方式为单个查询设置默认值以在所有小数上使用这个小数(25,13)?

【问题讨论】:

  • 不确定您阅读的内容,但 the documentation 用于乘法和除法运算符调用“3。如果比例大于 6 并且整数部分大于 32,则比例将设置为 6。在在这种情况下,整数部分和比例都会减少,结果类型是小数(38,6)。"
  • @Dan Guzman 我相信你应该把你的评论变成一个答案
  • @DanGuzman 这如何解释乘法和除法本身都产生规模 13,但链接时产生规模 6?问题基本上是添加额外的演员如何改变计算,因为 sql server 认为乘法也产生 13 比例(通过 SQL_VARIANT_PROPERTY)。
  • @DanGuzman Ahh,这是因为没有演员表,精度设置为 38 而不是 25,这是由额外演员表修复的..
  • @mpn275,完全正确。不幸的是,没有“给我我想要的精度和规模”查询提示。您需要指定适当的精度和比例,以最大限度地满足您的需求。

标签: sql-server decimal


【解决方案1】:

以下是来自precision, scale, and length documentation 的相关摘录,用于十进制乘法和除法行为的上下文。

+--------------------------------------+-------------------------------------+---------------------+
|              Operation               |          Result precision           |   Result scale *    |
+--------------------------------------+-------------------------------------+---------------------+
| e1 * e2                              | p1 + p2 + 1                         | s1 + s2             |
| e1 / e2                              | p1 - s1 + s2 + max(6, s1 + p2 + 1)  | max(6, s1 + p2 + 1) |
+--------------------------------------+-------------------------------------+---------------------+

* The result precision and scale have an absolute maximum of 38. When a result precision is greater than 38, it's reduced to 38, and the corresponding scale is reduced to try to prevent truncating the integral part of a result. In some cases such as multiplication or division, scale factor won't be reduced, to maintain decimal precision, although the overflow error can be raised.

In multiplication and division operations, we need precision - scale places to store the integral part of the result. The scale might be reduced using the following rules:

1. The resulting scale is reduced to min(scale, 38 - (precision-scale)) if the integral part is less than 32, because it can't be greater than 38 - (precision-scale). Result might be rounded in this case.

2. The scale won't be changed if it's less than 6 and if the integral part is greater than 32. In this case, overflow error might be raised if it can't fit into decimal(38, scale)

3. The scale will be set to 6 if it's greater than 6 and if the integral part is greater than 32. In this case, both integral part and scale would be reduced and resulting type is decimal(38,6). Result might be rounded to 6 decimal places or the overflow error will be thrown if the integral part can't fit into 32 digits.

第 3 项适用于您问题中的第三个查询,可以通过 sp_describe_first_result_set 观察到:

EXEC sp_describe_first_result_set N'
select cast(7 as decimal(25,13))*cast(15 as decimal(25,13))/cast(11 as decimal(25,13)) --= 9.545454
';

上述查询中的 system_type_name 显示 decimal(38,6)。由于表达式结果比例 6 不足以满足您的需要,因此将乘法表达式的显式 CAST 转换为精度较低的十进制类型(就像您在问题的最后一个查询中所做的那样)将为结果提供更大的比例类型,但溢出风险增加。

显式 CASTdecimal(25, 13) 导致结果类型为 decimal(38, 13)

EXEC sp_describe_first_result_set N'
select cast(
       cast(7 as decimal(25,13))*cast(15 as decimal(25,13)) as decimal(25,13))/cast(11 as decimal(25,13)) --= 9.5454545454545
';

【讨论】:

    【解决方案2】:

    我尝试做乘法然后转换成十进制

    select cast(7*15 as decimal(25,13))/cast(11 as decimal(25,13))
    

    【讨论】:

    • 这不起作用,因为 7 和 15 的乘法可能已经减少到 6 位小数,就像在我的情况下,所有数据库小数列都有小数 (38,20)。之后的转换只会添加零。
    猜你喜欢
    • 1970-01-01
    • 2022-10-13
    • 2019-10-23
    • 2012-01-14
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    相关资源
    最近更新 更多