代码之家  ›  专栏  ›  技术社区  ›  Stefan Steiger

为什么MS SQL Server(所有版本)将1.0/12.0转换为数字(8,6)?

  •  4
  • Stefan Steiger  · 技术社区  · 6 年前

    我想解释一下价值相差101.10的原因。

    303'300000/12大约是25275000。
    然而,根据MS-SQL,它是25'274'898.90。

    考虑以下(简化)SQL语句:

    SELECT 
         303300000.00/12.0 AS a 
        ,1.0/12.0*303300000.00 AS b
        ,1.0/12.0 AS omg 
        ,1.0/CAST(12.0 AS float) AS expected 
        ,0.083333*303300000.0 AS r1 
        ,0.083333333333333300 * 303300000.0 AS r2
    

    astounding results

    浮动

    但很显然 decimal (8,6)

    CREATE VIEW dbo._Test
    AS
    SELECT 1.0/12.0 as xxx
    
    
    
    SELECT 
         COLUMN_NAME
        ,DATA_TYPE
        ,NUMERIC_PRECISION
        ,NUMERIC_SCALE
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '_Test' 
    
    
    DROP VIEW dbo._Test
    

    这种疯狂有什么原因吗?
    如何确定精度?
    是否有强制浮点的符号,而不需要强制转换语句?

    如果我在PostgreSQL上运行相同的查询,pg会正确执行。。。

    postgre does it right

    3 回复  |  直到 6 年前
        1
  •  6
  •   Thom A    6 年前

    文档中对此进行了解释: Precision, scale, and Length (Transact-SQL)

    操作数表达式表示为表达式e1,精度为 p1和标度s1,表达式e2,精度p2和标度s2。 为表达式的数据类型定义的精度和比例。

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

    这里的重要部分是最后一部分。在你的情况下,你有一个 decimal(2,1) decimal(3,1) . 为了精确起见,这将导致:

     2 - 1 + 1 + max(6,1 + 3 + 1) = 2 + max(6,5) = 2 + 6 = 8
    

    max(6,1+3+1) = max(6,5) = 6
    

    取结果值,结果得到 decimal(8,6)

        2
  •  2
  •   Gordon Linoff    6 年前

    设置乘法和除法的精度和刻度 decimal / numeric 是一种神秘的艺术。SQL Server确实解释了 documentation :

    在乘法和除法运算中,我们需要精确刻度 使用以下规则减少:

    1. 如果整数部分小于32,则生成的刻度将减小为min(刻度,38(精密刻度)),因为 在这种情况下。

    2. 如果无法放入小数点(38,小数位数),则将其提升

    3. 如果比例尺大于6且整数部分大于32,则将其设置为6。在这种情况下,积分部分和 比例将减小,结果类型为十进制(38,6)。结果 可能四舍五入到小数点后6位,否则将引发溢出错误 如果整数部分不能容纳32位。

    在那个解释中,我看到“6”,所以这解释了比例部分。我确信精确性来自同样直接的逻辑。

        3
  •  0
  •   TT. abdelrhman raafat    6 年前

    想想这个事实 literals like 1.0 and 12.6 are of decimal (numeric) type . 1.0表示精度2和刻度1,12.0表示精度3和刻度2。

    because the highest precendence of the types is decimal (两种类型都是十进制的)。

    至于 precision and scale of the expression

    expr        precision                           scale
    e1 / e2     p1 - s1 + s2 + max(6, s1 + p2 + 1)  max(6, s1 + p2 + 1)
    

    所以,