交易 SQL: case when 1=1 then 0.5 else ceiling(sh) end /* returns 1 (!) 为什么? */

Transact SQL: case when 1=1 then 0.5 else ceiling(sh) end /* returns 1 (!) why? */

-- Transact SQL:  case when 1=1 then 0.5 else ceiling(sh) end   /* returns 1  (!) why? */
declare @T table (h decimal(2,1)) 
insert @T (h) values (1.0)
select 
case when 1=1 then 0.5 else ceiling(sh) end   /* returns 1  (!) why? */
from @T T1
join (select sum(h) as sh from @T )T2  on 1 = 1

documentation

中所述

When an operator combines two expressions of different data types, the rules for data type precedence specify that the data type with the lower precedence is converted to the data type with the higher precedence. If the conversion is not a supported implicit conversion, an error is returned. When both operand expressions have the same data type, the result of the operation has that data type.

在你的情况下转换为 int 因为具有更大的优先级。

sql demo

declare @T table (h decimal(2,1)) 
insert @T (h) values (1.0)
select 
case when 1=1 then 0.5 else ceiling(sh)*1.0 end  -- << convert to float
from @T T1
join (select sum(h) as sh from @T )T2  on 1 = 1

答案与 int 数据类型无关

  • 文字 0.5 的数据类型为 decimal(1,1)
  • decimal(p,s) return 类型的结果上应用 CEILING decimal(p,0)
  • decimal(p,s) return 上应用 SUM 结果 输入 decimal(38,s)
  • 使用混合 CASE 表达式可以 return decimal(p1,s1)decimal(p2,s2) 结果将使用与 UNION 时相同的规则-ing 这些数据类型并具有精度 (*) max(s1, s2) + max(p1-s1, p2-s2) 的规模和 max(s1, s2)
  • 的规模

* The result precision and scale have an absolute maximum of 38. When a result precision is greater than 38, it is reduced to 38, and the corresponding scale is reduced to try to prevent the integral part of a result from being truncated. (source)

因此您的列 h 的数据类型为 decimal(2,1),应用 SUM 时的数据类型为 decimal(38,1),应用的数据类型为 CEILINGdecimal(38,0)。然后在 CASE 表达式中使用 decimal(1,1)

max(s1, s2) + max(p1-s1, p2-s2)
max( 0,  1) + max(   38,     0) = 1 + 38 = 39

max(s1, s2) = max(0, 1) = 1

因此,所需的结果数据类型为 decimal(39,1)。这大于 38,所以你得到上面描述的比例缩减并最终得到 decimal(38,0) - 0.5 在转换为该数据类型时四舍五入为 1

如果您希望保持最终结果的精度,您可以使用

case when 1=1 then 0.5 else CAST(ceiling(sh) AS decimal(38,1)) end 

这有一个很小的额外溢出风险,但要被它击中,总和需要加起来为以下值之一

  • 9999999999999999999999999999999999999.5
  • 9999999999999999999999999999999999999.6
  • 9999999999999999999999999999999999999.7
  • 9999999999999999999999999999999999999.8
  • 9999999999999999999999999999999999999.9

这样 SUM 本身适合 38,1CEILING 不适合。

更多说明:

select CEILING(170.00/6.00),CEILING(170/6),170.00/6.00,170/6

结果:

29  28  28.333333   28