除了带有游标的简单(=无聊)解决方案之外,您还可以通过创建一个聚合函数(或者更确切地说,2 个聚合函数,一个用于计算余额 1,一个用于计算余额 2)来完成此操作。问题是您只能对聚合函数使用一个参数,因此该参数必须是复合类型。在伪代码中(我已经很久没有使用 Oracle):
CREATE TYPE tuple_type(amt number, bal1 number, bal2 number);
CREATE FUNCTION calc_bal1(arg IN tuple_type) RETURN number AGGREGATE USING some_implementing_type;
CREATE FUNCTION calc_bal2(arg IN tuple_type) RETURN number AGGREGATE USING some_implementing_type;
然后您可以使用分析函数查询它们。如果您只对每个帐户的最终值感兴趣,您可以执行以下操作:
SELECT t1.acct_no,
calc_bal1(tuple_type(t2.amt, t1.bal1, t1.bal2)) OVER (PARTITION BY t1.acct_no ORDER BY t2.datenum),
calc_bal2(tuple_type(t2.amt, t1.bal1, t1.bal2)) OVER (PARTITION BY t1.acct_no ORDER BY t2.datenum)
FROM table1 t1
JOIN (SELECT acct_no, datenum, amt FROM table2
UNION ALL
SELECT acct_no, 0, 0) t2
ON t1.acct_no = t2.acct_no;
WHERE t1.datenum = 0;
如果您想要每个单笔交易,请执行以下操作:
SELECT t1.acct_no,
calc_bal1(tuple_type(t2.amt, t1.bal1, t1.bal2))
OVER (PARTITION BY t1.acct_no
ORDER BY t2.datenum
ROWS BETWEEN UNBOUNDED PRECEEDING AND CURRENT ROW),
calc_bal1(tuple_type(t2.amt, t1.bal1, t1.bal2))
OVER (PARTITION BY t1.acct_no
ORDER BY t2.datenum
ROWS BETWEEN UNBOUNDED PRECEEDING AND CURRENT ROW)
FROM table1 t1
JOIN (SELECT acct_no, datenum, amt FROM table2
UNION ALL
SELECT acct_no, 0, 0) t2
ON t1.acct_no = t2.acct_no;
您也可以使用游标而不是聚合来执行此操作(这很可能具有糟糕的性能):
CREATE FUNCTION calc_bal1(c IN sys.ref_cursor, bal1 IN number, bal2 IN number) RETURN number AS ...;
CREATE FUNCTION calc_bal2(c IN sys.ref_cursor, bal1 IN number, bal2 IN number) RETURN number AS ...;
如果你想要所有行:
SELECT t1.acct_no,
calc_bal1(CURSOR(SELECT amt FROM table2 x WHERE x.acct_no = t1.acct_no AND x.datenum <= t2.datenum ORDER BY x.datenum), t1.bal1, t1.bal2),
calc_bal2(CURSOR(SELECT amt FROM table2 x WHERE t2.acct_no = t1.acct_no AND x.datenum <= t2.datenum ORDER BY t2.datenum), t1.bal1, t1.bal2)
FROM table1 t1
JOIN (SELECT acct_no, datenum, amt FROM table2
UNION ALL
SELECT acct_no, 0, 0) t2
ON t1.acct_no = t2.acct_no;
如果您只想要最终值:
SELECT t1.acct_no,
calc_bal1(CURSOR(SELECT amt FROM table2 t2 WHERE t2.acct_no = t1.acct_no ORDER BY t2.datenum), t1.bal1, t1.bal2),
calc_bal2(CURSOR(SELECT amt FROM table2 t2 WHERE t2.acct_no = t1.acct_no ORDER BY t2.datenum), t1.bal1, t1.bal2)
FROM table1 t1;