使用curs查找运行总计

时间:2017-04-18 00:11:23

标签: tsql

我有两个表Accountmaster和Transactionmaster

accountmaster有专栏

ACID
NAME
地址
CLRbal
Branchid

Transactionmaster有列

TransNo
DOT
Txntype
Txnamt
ACID
Branchid

使用游标,我希望每当交易类型,现金提取或现金存款发生时,clrbal的运行总​​额就会打印在变量中。当运行总计为-ve

时,也会打印错误消息

2 个答案:

答案 0 :(得分:1)

我试过这样的事情。 在o / p我只能获得第一个cashdeposit transaction amt作为运行总计

create TABLE #v
(
  acid INT , 
  TXNTYPE NCHAR(3), 
  TXNAMT MONEY,
  rt INT,
  --constraint fk_acid foreign key(acid) references accountmaster(acid)
);

INSERT #v(acid, TXNTYPE, TXNAMT) 
  SELECT DISTINCT ACID,TXNTYPE, TXNAMT
  FROM dbo.TRANSACTIONMASTER


DECLARE
 @rt INT, 
 @ACID INT,
 @TXNTYPE NCHAR(3),
 @TXNAMT  MONEY;
SET @rt = 0;

DECLARE c CURSOR 
  FOR SELECT ACID, TXNTYPE,TXNAMT FROM #v 

OPEN c;

FETCH c INTO @ACID, @txntype,@txnamt;

if @TXNTYPE='cd'
BEGIN
  SET @rt = @rt + @TXNAMT;
  UPDATE #v SET rt = @rt WHERE acid = @ACID;
  FETCH c INTO @acid,@txntype, @txnamt;
END
if @TXNTYPE='cw'
BEGIN
  SET @rt = @rt - @TXNAMT;
  UPDATE #v SET rt = @rt WHERE ACID = @ACID;
  FETCH c INTO @acid,@txntype, @txnamt;
END


CLOSE c; DEALLOCATE c;

答案 1 :(得分:0)

首先让我们把一些样本数据放在一起。我要添加一个TXNDATE,以便我们可以排序。为简洁起见,我们将忽略NULL,MONEY数据类型等主题。

IF OBJECT_ID('tempdb..#v') IS NOT NULL DROP TABLE #v;
CREATE TABLE #v
(
  TXNDATE  DATE, -- something to sort by
  acid     INT , 
  TXNTYPE  NCHAR(3), 
  TXNAMT   MONEY,
  rt       INT
);

--INSERT #v(acid, TXNTYPE, TXNAMT) 
--    SELECT DISTINCT ACID,TXNTYPE, TXNAMT
--    FROM dbo.TRANSACTIONMASTER;

INSERT #v(TXNDATE, acid, TXNTYPE, TXNAMT)
VALUES 
('20170102', 1, 'DBT', 12.01), ('20170104',1, 'CRD', 1155), ('20170112',1,'CRD',23.37),
('20170302',1, 'CRD', 124.2), ('20170303', 1, 'DBT', 819.29), ('20170402',1, 'CRD', 11.12);

我无法访问transactionmaster,因此我只会编写一些示例数据。

INSERT #v(TXNDATE, acid, TXNTYPE, TXNAMT)
VALUES 
('20170102', 1, 'DBT', 12.01), ('20170104',1, 'CRD', 1155), ('20170112',1,'CRD',23.37),
('20170302',1, 'CRD', 124.2), ('20170303', 1, 'DBT', 819.29), ('20170402',1, 'CRD', 11.12);

现在我们有了

TXNDATE    acid        TXNTYPE TXNAMT                rt
---------- ----------- ------- --------------------- -----------
2017-01-02 1           DBT     12.01                 NULL
2017-01-04 1           CRD     1155.00               NULL
2017-01-12 1           CRD     23.37                 NULL
2017-03-02 1           CRD     124.20                NULL
2017-03-03 1           DBT     819.29                NULL
2017-04-02 1           CRD     11.12                 NULL

我假设运行总计将按日期排序。然而,首先,对于性能,我们确实需要该日期的聚簇索引。

CREATE CLUSTERED INDEX cl_v ON #v(TXNDATE);

现在我对游标知之甚少,只是说要用FORWARD_ONLY和READ_ONLY运行游标。我接近这个的方式是......

<强> 1。古怪的更新

DECLARE @runningTotal INT = 0;

UPDATE #v
SET @runningTotal = RT = (@runningTotal + CASE TXNTYPE WHEN 'DBT' THEN -TXNAMT ELSE TXNAMT END)
FROM #v WITH TABLOCKX
OPTION (MAXDOP 1);

执行计划利用聚集索引并执行得非常好。

enter image description here

在我的系统上,成本约为0.013 ......

<强> 2。 WINDOW Aggreage函数,(SUM OVER)

WITH CTE AS
(
   SELECT *, 
     RT_NEW = 
       SUM(CASE TXNTYPE WHEN 'DBT' THEN -TXNAMT ELSE TXNAMT END) OVER (ORDER BY TXNDATE)
   FROM #v
)
UPDATE CTE
SET rt=RT_NEW;

执行计划也很好。

enter image description here

每个都产生这个结果

TXNDATE    acid        TXNTYPE TXNAMT                rt
---------- ----------- ------- --------------------- -----------
2017-01-02 1           DBT     12.01                 -12
2017-01-04 1           CRD     1155.00               1143
2017-01-12 1           CRD     23.37                 1166
2017-03-02 1           CRD     124.20                1290
2017-03-03 1           DBT     819.29                471
2017-04-02 1           CRD     11.12                 482