sql 中的舍入误差


DECLARE @TAX VARCHAR(30)=120.45
DECLARE @TaxRoundOf VARCHAR(30)
SET @TaxRoundOf=ROUND(@TAX,1)
SELECT @TaxRoundOf

这给出了结果(@TaxRoundOf=120.5(

DECLARE @TAX VARCHAR(30)=146.45
DECLARE @TaxRoundOf VARCHAR(30)
SET @TaxRoundOf=ROUND(@TAX,1)
SELECT @TaxRoundOf

这给出了结果(@TaxRoundOf=146.4(

但是我需要返回146.50. 为什么两个结果不匹配? 有人可以帮忙吗?

由于您使用VARCHAR来存储数字,SQL Server 必须进行隐式转换以在幕后浮动,这会对您的计算产生连锁反应。您可以使用以下查询重现此内容:

SELECT  ROUND(CONVERT(FLOAT, 120.45),1),            -- 120.5
ROUND(CONVERT(FLOAT, 146.45),1),            -- 146.4
ROUND(CONVERT(DECIMAL(10, 2), 120.45),1),   -- 120.50
ROUND(CONVERT(DECIMAL(10, 2), 146.45),1)    -- 146.50

由于浮点数不精确,146.45 不能精确地表示为浮点数,最终被存储为一个非常小的数字,因此当它传递给 round 函数时,它会向下舍入,而不是向上舍入。

如上述查询中的第 3 列和第 4 列所示,解决方案是使用更精确的数据类型。

你可以使用这个:

SET @TaxRoundOf=ROUND(10 * CAST(@TAX AS FLOAT)) / 10

而不是:

SET @TaxRoundOf=ROUND(@TAX,1)

演示

PS 正如@GarethD已经提到的,我不会将@TAX用作VARCHAR类型。

你也可以依靠舍入numeric而不是将字符串转换为float,这可能会丢失信息。

将字符串转换为numeric然后舍入:

select round(cast('146.45' as numeric(18,2)), 1)
-- 146.50

十进制常量已经是一个decimal所以没有必要强制转换它:

select round(146.45, 1)
-- 146.50

最新更新