簡體   English   中英

MySql 查詢運行平衡校正

[英]MySql Query for Running Balance Correction

請有人幫我做一個 MySql 查詢以進行運行平衡校正。

實際上,我們有很多來自其他應用程序的臟數據。 有時我們在正常運行余額計算中得到負余額。

從我得到答案之前的問題開始,但我希望僅在正常余額計算為負時才首先計算信用交易,因此如果余額不是負數,則同一日期內的借記和貸記順序不應改變

這是表格示例:

trx_no  trx_date    Opening debit   credit 
1       2019-10-01  200     0       100    
2       2019-10-02  200     0       100     
3       2019-10-03  200     100     0       
4       2019-10-03  200     400     0      
5       2019-10-03  200     0       200      
6       2019-10-04  200     0       100      
7       2019-10-05  200     100     0 
8       2019-10-05  200     0       400

對於正常余額計算,我們得到負余額:

trx_no  trx_date    Opening debit   credit   balance
    1   2019-10-01  200     0       100      300
    2   2019-10-02  200     0       100      400
    3   2019-10-03  200     100     0        300
    4   2019-10-03  200     400     0        -100  <- negative balance
    5   2019-10-03  200     0       200      100
    6   2019-10-04  200     0       100      200
    7   2019-10-05  200     100     0        100
    8   2019-10-05  200     0       400      500

這是我從@forpas 得到的查詢(非常感謝):

SELECT
    t1.trx_no,
    t1.trx_date,
    t1.Opening,
    t1.debit,
    t1.credit,
    t1.Opening + (
      SELECT SUM(t2.credit - t2.debit)
      FROM MyTable t2 
      WHERE 
        concat(t2.trx_date, t2.debit > t2.credit, lpad(t2.trx_no, 10, '0')) <=
        concat(t1.trx_date, t1.debit > t1.credit, lpad(t1.trx_no, 10, '0'))
    ) AS balance
FROM MyTable t1
ORDER BY concat(t1.trx_date, t1.debit > t1.credit, lpad(t1.trx_no, 10, '0'))

以下是上述查詢的結果,沒有負余額,但 trx_no 8 在 trx_no 7 之前排序:

trx_no  trx_date    Opening debit   credit   balance
    1   2019-10-01  200     0       100      300
    2   2019-10-02  200     0       100      400
    5   2019-10-03  200     0       200      600
    3   2019-10-03  200     100     0        500
    4   2019-10-03  200     400     0        100
    6   2019-10-04  200     0       100      200
    8   2019-10-05  200     0       400      600
    7   2019-10-05  200     100     0        500

我們需要的結果如下。 僅在余額為負數時才首先計算信用交易。 因此,如果余額不是負數,則訂單不應更改:

trx_no  trx_date    Opening debit   credit   balance
    1   2019-10-01  200     0       100      300
    2   2019-10-02  200     0       100      400
    5   2019-10-03  200     0       200      600
    3   2019-10-03  200     100     0        500
    4   2019-10-03  200     400     0        100
    6   2019-10-04  200     0       100      200
    7   2019-10-05  200     100     0        100
    8   2019-10-05  200     0       400      500

這是演示

我認為這不能使用基於集合的代碼來完成,因為您需要預讀和回讀。 一些程序可以工作。 使用 cursor 和一個臨時表我幾乎可以做到這一點(您需要添加一些東西以確保累積余額不會 go 為負數)。 從你所說的第一筆交易永遠不會使余額為負,但我會檢查一下。 請注意,來自貸方池的收益可能來自於借方補償的借方的較晚日期 - 因為余額永遠不會 go 為負數,那么這應該不是問題(原文如此)。 當然,我不會期望表現會很棒。

DROP TABLE IF EXISTS T;
create table t
(trx_no int, trx_date date,    Opening int,debit int,  credit int);
insert into t values
(1    ,   '2019-10-01' , 200  ,   0     ,  100),    
(2    ,   '2019-10-02' , 200  ,   0     ,  100),    
(3    ,   '2019-10-03' , 200  ,   100   ,  0  ),     
(4    ,   '2019-10-03' , 200  ,   400   ,  0  ),    
(5    ,   '2019-10-03' , 200  ,   0     ,  200),      
(6    ,   '2019-10-04' , 200  ,   0     ,  100),      
(7    ,   '2019-10-05' , 200  ,   100   ,  0  ),
(8    ,   '2019-10-05' , 200  ,   0     ,  400);

DROP TABLE IF EXISTS stmT;
create table stmt
(trx_no int, trx_date date,    Opening int,debit int,  credit int, cumbal int);




drop procedure if exists p;
delimiter $$
create procedure p()
begin

 declare v_trx_no int;
 declare v_dt date;
 declare v_debit int;
 declare v_credit int;

 declare h_trx_no int;
 declare h_dt date;
 declare h_credit int;

 declare opbal int;
 declare rbal  int;
 declare done int default 0;
 declare cur cursor for select trx_no,trx_date,debit,credit from t order by trx_date,trx_no;
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

 select opening into opbal from t order by trx_no limit 1;
 set rbal = opbal;
 drop table if exists creditpool;
 create temporary table if not exists creditpool as select trx_no,trx_date,credit,0 as used from t where  credit > 0; 
 #select * from creditpool;
    open cur;
    cursorloop:loop
        fetch cur into v_trx_no,v_dt,v_debit,v_credit;
         if done = true then  
        leave cursorloop;
         end if;  
         if v_credit > 0 and exists (select 1 from creditpool where trx_no = v_trx_no and used = 0) then 
             if v_credit > 0 then
                 insert into stmt values (v_trx_no,v_dt,opbal,v_debit,v_credit, rbal + v_credit);
                 set rbal = rbal + v_credit;
                 update creditpool set used = 1 where trx_no = v_trx_no; 
            end if;
         end if;
         if v_debit > 0 and v_debit <= rbal then
             insert into stmt values (v_trx_no,v_dt,opbal,v_debit,v_credit, rbal - v_debit);
             set rbal = rbal - v_debit;
         elseif v_debit > 0 and v_debit > rbal then
             poolloop: loop
                        select trx_no,trx_date,credit
                            into h_trx_no,h_dt,h_credit
                            from creditpool
                            where used = 0 
                            order by trx_date,trx_no limit 1;
                        insert into stmt values (h_trx_no,h_dt,opbal,0,h_credit, rbal + h_credit);
                        set rbal = rbal + h_credit;
                        update creditpool set used = 1 where trx_no = h_trx_no; 

                        if v_debit <= rbal then
                            insert into stmt values (v_trx_no,v_dt,opbal,v_debit,v_credit, rbal - v_debit);
                            set rbal = rbal - v_debit;
                            leave poolloop;
                        end if;
             end loop poolloop;           
         end if;
    end loop cursorloop;
    close cur;
end $$
delimiter ;
truncate stmt;
call p();
select * from stmt;

+--------+------------+---------+-------+--------+--------+
| trx_no | trx_date   | Opening | debit | credit | cumbal |
+--------+------------+---------+-------+--------+--------+
|      1 | 2019-10-01 |     200 |     0 |    100 |    300 |
|      2 | 2019-10-02 |     200 |     0 |    100 |    400 |
|      3 | 2019-10-03 |     200 |   100 |      0 |    300 |
|      5 | 2019-10-03 |     200 |     0 |    200 |    500 |
|      4 | 2019-10-03 |     200 |   400 |      0 |    100 |
|      6 | 2019-10-04 |     200 |     0 |    100 |    200 |
|      7 | 2019-10-05 |     200 |   100 |      0 |    100 |
|      8 | 2019-10-05 |     200 |     0 |    400 |    500 |
+--------+------------+---------+-------+--------+--------+
8 rows in set (0.00 sec)

請注意,結果與您想要的結果略有不同,因為僅在需要時才進行拍攝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM