Note: I'm not sure all the answerers are handling fractional values the way you intended. My version treats 0.4 as the cutoff for rounding up. All values where the fractional component is between 0.4 and 0.9 are treated the same way.
Doing it without a CASE
block is not impossible. I suspect this isn't the shortest expression either.
declare @t as table (d decimal(5, 1) not null);
insert into @t
values (2.0), (2.1), (2.2), (2.3), (2.4), (2.5), (2.6), (2.7), (2.8), (2.9);
select d, d + 0.1 + (round(-0.8 + d % 1, 0) + 1) * (0.9 - d % 1)
from @t;
I'm assuming the numbers are positive since you didn't specify behavior regarding negatives.
As for the other approach to rounding: this is algebraically equivalent to the other answer but the logic might be more obvious this way.
d + 0.1 + 0.5 * (1 - abs(sign(d % 1 - 0.4)))
Here's another expression built on functions. Of course coalesce
does expand to a case
expression internally.
floor(d) + 0.1 + coalesce(nullif(d % 1, 0.4), 0.9)
The problem with your approach is in the implicit casts. And in those casts you're assuming that dot character is always the decimal mark.
EDIT:
If you're sure that the fractional portion of the input never exceeds 0.4 then I can think of another easy calculation.
d + 0.1 + floor(d % 1 * 2.5) * 0.5
These little tricks were more useful before SQL platforms had case
expressions. I think it's not likely that these options really have any efficiency benefit.