Tôi không nghĩ rằng điều này có thể được thực hiện bằng cách sử dụng mã dựa trên bộ vì bạn cần đọc trước và đọc lại. Một cái gì đó thủ tục có thể hoạt động. Sử dụng con trỏ và một bảng tạm thời, tôi có thể thực hiện được khá nhiều điều đó (bạn cần thêm nội dung để đảm bảo rằng số dư tích lũy không bị âm). Theo những gì bạn nói, giao dịch đầu tiên không bao giờ có thể lấy số dư âm nhưng tôi sẽ kiểm tra điều đó. Xin lưu ý rằng số dư từ nhóm tín dụng có thể đến muộn hơn số nợ mà khoản nợ được bù - vì số dư không bao giờ có thể âm nên điều đó không phải là vấn đề (sic). Và tất nhiên tôi sẽ không mong đợi hiệu suất trở nên tuyệt vời.
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)
Lưu ý rằng kết quả hơi khác so với kết quả mong muốn của bạn bởi vì kết quả chỉ xảy ra khi được yêu cầu.