Transact SQL: случай, когда 1 = 1, тогда 0.5 else limit (sh) end / * возвращает 1 (!) Почему?* / - PullRequest
0 голосов
/ 30 ноября 2018
-- 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 голосов
/ 01 декабря 2018

Ответ не имеет ничего общего с 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применяется к этому 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

Таким образом, желаемый тип данных результата будет 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,1, а CEILING - нет.

0 голосов
/ 30 ноября 2018

Как объясняется в документации

Когда оператор объединяет два выражения разных типов данных, правила для приоритета типа данных указывают, что тип данных с более низким приоритетом имеет видпреобразован в тип данных с более высоким приоритетом.Если преобразование не поддерживается неявным преобразованием, возвращается ошибка.Когда оба выражения операнда имеют одинаковый тип данных, результат операции имеет этот тип данных.

В вашем случае преобразуется в 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
...