如何使用VB.NET在SQL Server数据库中维护运行总计?

时间:2011-03-04 12:28:35

标签: sql-server vb.net sql-server-2008

我正在使用Visaul Studio 2010构建Windows窗体应用程序来维护SQL Server 2008数据库中的表。该表名为CASHBOOK,以下是更多详细信息:

DATE    | DESCRIPTION    | DEBIT   | CREDIT    | BALANCE
--------|----------------|---------|-----------|---------
1/1/2011| CASH BALANCE   |         |           | 5000
1/1/2011| SALES          |  2500   |           | 7500
2/1/2011| PURCHASE       |         |  3000     | 4500
2/1/2011| RENT           |         |  4000     |  500
2/1/2011| SALES          |  5000   |           | 5500

我可以使用CASHBOOKTABLEADAPTER.INSERT(...)进行适当的插入,但我的问题是如何更新BALANCE列?

6 个答案:

答案 0 :(得分:1)

答案 1 :(得分:0)

您可以尝试使用子查询进行插入,如下所示:

INSERT INTO CASHBOOK  ( DESCRIPTION, DEBIT, BALANCE )
'asdf', 2500, SELECT TOP(1) BALANCE FROM CASHBOOK + 2500

答案 2 :(得分:0)

这有点沉重,但这是一种用平衡信息更新整个表的方法。

update
   a
set
   a.Balance = (
      select sum(isnull(x.debit, 0.0) - isnull(x.credit, 0.0))
      from cashbook x
      where x.Date < a.Date
      or (x.Date = a.Date and x.ID <= a.ID)
   ) + (
      select top 1 y.Balance
      from cashbook y
      where y.debit is null
      and y.credit is null
      order by y.ID
   )
from
   cashbook a

现在只有在你必须在表格中保持平衡时才有用。更合适的解决方案可能是创建一个包含此逻辑的UDF,并调用该UDF以仅在需要时计算特定行的余额字段。这完全取决于您的使用情况。

create function dbo.GetBalance(@id int) returns decimal(12, 2) as
begin

declare @result decimal(12, 2) = 0.0

select
       @result = (
          select sum(isnull(x.debit, 0.0) - isnull(x.credit, 0.0))
          from cashbook x
          where x.Date < a.Date
          or (x.Date = a.Date and x.ID <= a.ID)
       ) + (
          select top 1 y.Balance
          from cashbook y
          where y.debit is null
          and y.credit is null
          order by y.ID
       )
from
   cashback a
where
   a.ID = @id

return @result

end

答案 3 :(得分:0)

为什么需要?这应该作为报告/查看功能计算。我建议创建一个具有运行总列的视图(实现此目的的各种方法)。

或者,如果您在VB.Net中查看此内容,请在您的应用中进行计算。

答案 4 :(得分:0)

我同意Joel,你应该在运行时计算它,而不是将运行总计存储在数据库中。这是一个如何在sql server中使用递归cte计算运行总数的示例:

declare @values table (ID int identity(1,1), Value decimal(4,2))
declare @i int

insert into @values values (1.00)
insert into @values values (2.00)
insert into @values values (3.00)
insert into @values values (4.00)
insert into @values values (5.00)
insert into @values values (6.00)

select @i=min(ID) from @values

;with a as
(
    select ID, Value, Value as RunningTotal
    from @values
    where ID=@i

    union all
    select b.ID, b.Value, cast(b.Value + a.RunningTotal as decimal(4,2)) as RunningTotal
    from @values b
        inner join a
            on b.ID=a.ID+1

)
select * from a

这是一个关于递归查询的博客:Recursive CTEs

同样here's关于运行总计的冗长讨论。

答案 5 :(得分:0)

递归CTE的一个潜在问题是最大深度限制为32767,这在生产环境中可能是禁止的。

在此解决方案中,您将添加一个对事务序列有序的id列,然后更新余额列。

declare @t table(id int identity(1,1) not null
, [DATE] date not null
, [DESCRIPTION] varchar(80) null
, [DEBIT] money not null default(0)
, [CREDIT] money not null default(0)
, [BALANCE] money not null default(0)
);

declare @bal money=0;

insert into @t([DATE],[DESCRIPTION],[DEBIT],[CREDIT],[BALANCE])
select '1/1/2011','CASH BALANCE',0,0,5000 UNION ALL
select '1/1/2011','SALES',2500,0,0 UNION ALL
select '2/1/2011','PURCHASE',0,3000,0 UNION ALL
select '2/1/2011','RENT',0,4000,0 UNION ALL
select '2/1/2011','SALES',5000,0,0;


set @bal=(select top 1 [BALANCE] from @t order by id); /* opening balance is stored but not computed, so we simply look it up here. */

update t
set @bal=t.[BALANCE]=(t.[DEBIT]-t.[CREDIT])+@bal
output
inserted.*
from @t t
left join @t t0 on t0.id+1=t.id; /*should order by id by default, but to be safe we force the issue here. */