3

我有一个执行大量计算的存储过程,将结果存储在几个临时表中。最后计算总和并舍入到小数点后两位并存储在临时表中并选择它。

所有中间和最终临时表都具有数据类型 float 用于关注的列。

原始场景:

Declare @Intermediate table
{
 --several other columns

Labor float

--several other columns
};

---Lots of calculation ---xx-----

Declare @Final table
{
 --several other columns

LaborTotal float

--several other columns
};

INSERT INTO @Final  SELECT ROUND(ISNULL((SELECT SUM([Labor]) FROM @Intermediate ),0),2)  AS LaborTotal;

SELECT * FROM @Final;

Result: 7585.22  --> when rounded  //Here is the error Expecting 7585.23
        7585.225 --> when not rounded

测试用例 :

   DECLARE @test float = 7585.225;
   SELECT ROUND(@test,2) AS Result; --> results 7585.23

   SELECT ROUND(7585.225,2) AS Result --> results 7585.23

将单个值插入临时表,然后计算总和

DECLARE @TmpTable table
(
 MaterialAmount float
 ,LaborAmount float
);

INSERT INTO @TmpTable VALUES (12.10,1218.75);
INSERT INTO @TmpTable VALUES (12.10,1090.125);
INSERT INTO @TmpTable VALUES (12.10,900);
INSERT INTO @TmpTable VALUES (12.10,1632.6);
INSERT INTO @TmpTable VALUES (12.10,1625);
INSERT INTO @TmpTable VALUES (12.10,1118.75);


SELECT ROUND(ISNULL((SELECT SUM(MaterialAmount) FROM @TmpTable), 0),2) AS MatSum,
       ISNULL((SELECT SUM(LaborAmount) FROM @TmpTable), 0) AS LabSumUnrounded, --> 7585.225
       ROUND(ISNULL((SELECT SUM(LaborAmount) FROM @TmpTable), 0),2) AS LabSum;  --> 7585.23

SELECT ROUND(SUM(MaterialAmount),2),
       ROUND(SUM(LaborAmount),2)   ---> 7585.23
   FROM @TmpTable;

任何想法/建议为什么我在原始场景中得到 0.01 的差异,同时在所有测试用例中获得准确的值?提前致谢。

4

3 回答 3

5

这是因为您使用的是浮点数据库类型。

浮点数不应该用于表示需要精度的值,因为它们存储为近似值,不同的操作会给你不同的结果。

在 sql server 中,您可以使用小数和数字数据类型来获得数值精度:http: //msdn.microsoft.com/en-us/library/ms187746.aspx

于 2013-09-09T15:33:04.873 回答
0

试试这个方法:

   SELECT ROUND(@test,2) AS Result; --> results 7585.23
   SELECT ROUND(convert(float,7585.225),2) AS Result --> results 7585.23

当您将值存储为浮点时,它存储近似值但不存储精确值,当您想要存储精确值时使用小数、金钱或小钱数据类型。在您的示例中,当我将数值转换为浮点数时,它存储了数字的近似值。

http://msdn.microsoft.com/en-us/library/ms187912%28v=sql.105%29.aspx

于 2013-09-09T15:30:08.470 回答
0

在显示结果之前,您可能会遇到某种精度错误。尝试这样的事情:

SELECT ROUND(ROUND(ISNULL((SELECT SUM([Labor]) FROM @Intermediate ),0),3) ,2)

ROUND 到 3 的内部实例去掉了那些讨厌的小数,只剩下 7585.225,外部 ROUND 实际上做了它应该做的事情。

于 2021-11-09T17:20:47.507 回答