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

Ste*_*ger 4 sql t-sql sql-server sql-server-2008 sql-server-2016

我试图解释101.10的价值差异.

303'300'000/12约为25'275'000.
但是,根据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
Run Code Online (Sandbox Code Playgroud)

惊人的结果

我以为自从我写了1.0/12.0后它就会变成浮动
(这本身是愚蠢的,但这是另一个故事),
但显然,它是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
Run Code Online (Sandbox Code Playgroud)

这种疯狂有什么理由吗?
它如何确定精度?
有没有强制浮动的符号,而不需要演员声明?

如果我在PostgreSQL上运行相同的查询,pg就是正确的...

postgre做对了

Lar*_*rnu 6

这在文档中进行了解释:精度,小数位数和长度(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)
Run Code Online (Sandbox Code Playgroud)

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

 2 - 1 + 1 + max(6,1 + 3 + 1) = 2 + max(6,5) = 2 + 6 = 8
Run Code Online (Sandbox Code Playgroud)

对于比例,我们得到:

max(6,1+3+1) = max(6,5) = 6
Run Code Online (Sandbox Code Playgroud)

获取结果值,结果得到一个decimal(8,6).