这个SQL代码是否容易出现舍入错误?

时间:2009-09-25 18:30:02

标签: sql-server decimal rounding currency

我发现了一些奇怪的行为,其中存储过程通过一两分钱返回不准确的结果。

这是代码(我没写过):

ALTER  PROCEDURE [dbo].[TN_GetSimpleBalance] 
    @custID int,
    @nBalance decimal (8,2) output
AS

declare @ArBalance as decimal (8,2)
declare @custStatusCode varchar (2)
declare @unbilledCallsAmount as decimal (8,2)

set @nBalance = 0

set @ArBalance = 0
set @custstatusCode = ''
set @unbilledCallsAmount = 0


SET NOCOUNT ON 

    select @unbilledCallsAmount = isnull(sum(callcharge+taxamount),0) 
    from call with (NOLOCK) where custid = @custID and callstatuscode in ('R', 'B')

    --get AR balance
    select @ArBalance = isnull(sum(amount),0) 
    from artran with (NOLOCK) 
    where custid = @custID AND POSTEDFLAG ='Y'

    set @nBalance = @unbilledCallsAmount + @ArBalance

@nBalance显示为零,即使另一个应用告诉我客户有$ .02。 callchargetaxamount都是货币数据类型。

这是我第一次遇到这种情况,但我正在将一些相关代码转移到生产中,并且已经“被要求”研究这个。

你有什么看法?钱和十进制数据类型之间是否存在奇怪之处?你认为还有什么可以解释这个吗?

4 个答案:

答案 0 :(得分:1)

我的代码中没有看到任何money数据类型,但我认为call.callcharge& call.taxamount是?我不知道手头的精度问题。

您可以做的最好的事情是尝试找到一个特定的测试用例,其中数据存在这种差异,并查看是否可以一致地重现它。然后,您可以一次性分离逻辑语句,并找出引入差异的位置。

你可能有一个空的电话费或空税吗? (null +( - $ 0.02))=>空值;也许

isnull(sum(callcharge+taxamount),0) 

应该是:

sum(isnull(callcharge, 0)+isnull(taxamount,0))
如果那些select语句没有返回任何记录,那么@unbilledCallsAmount或@ArBalance也可能为null。 HTH,

答案 1 :(得分:0)

哪些数据类型为callchargetaxamount?我将在该数据类型中进行所有计算,并在结束时转换为十进制。目前所有的中间变量都是小数,这意味着舍入误差复合。不要圆到最后。

答案 2 :(得分:0)

使用此功能时,尝试使用不同的硬编码值来调用callcharge& TAXAMOUNT:

declare @DecimalAmount as decimal (8,2)
declare @MoneyAmount as money

select @DecimalAmount = isnull(sum(callcharge+taxamount),0) 
      ,@MoneyAmount   = isnull(sum(callcharge+taxamount),0) 
    from (select CONVERT(money,1.43) AS callcharge, CONVERT(money,.83) AS taxamount
          UNION select CONVERT(money,1.43) AS callcharge, CONVERT(money,.01) AS taxamount
          UNION select CONVERT(money,1.43) AS callcharge, CONVERT(money,.99) AS taxamount
          UNION select CONVERT(money,1.43) AS callcharge, CONVERT(money,.03) AS taxamount
         ) dt

select @DecimalAmount,@MoneyAmount 

如果您在callcharge或taxamount中有3个或更多小数位,我只能得到不同的值。所以,如果你没有这样的数据,你就可以了。

答案 3 :(得分:0)

由于datatype precedence,您的资金(来自评论)列正在转换为十进制(8,2)。而money-> numeric (near end)是四舍五入的

因此@unbilledCallsAmount和@ArBalance都将被舍入,并且它们都是累积的。