SQL str()vs round()函数

时间:2014-06-25 08:21:45

标签: sql rounding

在使用str()函数时,我发现在某些情况下,舍入错误,而round()函数按预期工作。请看一下例子:

declare @v decimal(18,2) = 29.95
select str(@v, 18, 1)
--29.9
select round(@v, 1)
--30.00

set @v = 39.95
select str(@v, 18, 1)
--40.00
select round(@v, 1)
--40.00

任何人都可以解释为什么会这样吗?

EDIT1 : 我使用以下基本代码测试了不同的解决方法:

declare @v decimal(18,2) = 9.95
declare @r varchar(100)
declare @c int = 1000000
declare @ms int
declare @dt datetime2

set @dt = sysdatetime()

while @c > 0
begin
    set @r = --different roundings
    set @c = @c - 1
end

set @ms = DATEDIFF(ms, @dt, sysdatetime())
select @ms, @r

选项1(原始选项1,在某些情况下错误地回合):

str(@v, 18, 1)

选项2(稍加修改但正确舍入):

str(round(@v, 1), 18, 1)

选项3(双转换和舍入):

convert(varchar(20), convert(decimal(18,1), round(@v, 1)))

选项4(仅双转换):

convert(varchar(20), convert(decimal(18,1), @v))

结果: 选项1和2大约比最后两个慢2倍,但结果是右对齐的。最快的是选项4。

2 个答案:

答案 0 :(得分:1)

str()的参数是一个浮点数,因此您的十进制值会隐式转换为float(53),然后转换为字符串。所以你看到一个浮点舍入错误。

对您的查询稍作修改,您可以看到实际执行计划中发生了什么。

declare @v decimal(18,2) = 29.95
select top(1) str(@v, 18, 1)
<ScalarOperator ScalarString="str(CONVERT_IMPLICIT(float(53),[@v],0),(18),(1))">

答案 1 :(得分:0)

STR()的语法; STR(float_expression [,length [,decimal]])清楚地表明该数字是一个float_expression。因此,无论您给出的数字是多少,都会首先转换为FLOAT(n),默认值为n = 53。

所以

SELECT STR(4.65,5,1),SELECT STR(3.65,5,1)

等于:

SELECT STR(CAST(4.65 AS FLOAT(53)),5,1),STR(CAST(3.65 AS FLOAT(53)),5,1)

如果指定n,比如n = 4,它将给出你期望的答案(即; 4.7和3.7)

SELECT STR(CAST(4.65 AS FLOAT(4)),5,1),STR(CAST(3.65 AS FLOAT(4)),5,1)               --4.7,3.7