Transact SQL:1 = 1时为0.5,否则ceiling(sh)结尾/ *返回1(!)的情况为何? * /

时间:2018-11-30 15:26:58

标签: sql-server join sum case ceiling

-- 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

2 个答案:

答案 0 :(得分:3)

答案与int数据类型无关

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

*结果的精度和小数位数的绝对最大值为38。   结果精度大于38,则减小为38,并且   缩小相应规模,以防止   被截断的结果。 (source

因此您的列h的数据类型为decimal(2,1),当应用SUM时的数据类型为decimal(38,1),对其应用的CEILING的数据类型为{ {1}}。然后在decimal(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 。该值大于38,因此可以得到上述的比例缩减,最后得到decimal(39,1)-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,1不适合。

答案 1 :(得分:-3)

documentation

中所述
  

当运算符组合两个不同数据类型的表达式时,数据类型优先级规则将优先级较低的数据类型转换为优先级较高的数据类型。如果该转换不是受支持的隐式转换,则返回错误。当两个操作数表达式具有相同的数据类型时,运算结果将具有该数据类型。

在您的情况下,由于优先级较高,因此转换为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