递归 PL SQL 查询帮助
Posted
技术标签:
【中文标题】递归 PL SQL 查询帮助【英文标题】:Recursive PL SQL Query Help 【发布时间】:2011-07-28 18:23:23 【问题描述】:我有一张两张桌子。我想从这两个表中得到以下结果。任何帮助表示赞赏。
事件表
event_id | gross_amount | transaction_id
1 | 10 | 1
2 | 12 | 5
事务表
trx_id | debit | credit | link_trx_id
1 | 4 | 0 | null
2 | 0 | 2 | 1
3 | 0 | 1 | 2
4 | 3 | 0 | 3
5 | 0 | 5 | null
6 | 0 | 3 | 5
预期结果:
trx_id | debit | credit | current_gross | current_net
1 | 4 | 0 | 10 | 6
2 | 0 | 2 | 6 | 8
3 | 0 | 1 | 8 | 9
4 | 3 | 0 | 9 | 6
5 | 0 | 5 | 10 | 15
6 | 0 | 3 | 15 | 18
说明
如您所见,事务 1,2,3,4 落入一组,而 4,6 落入另一组。对于每笔交易都需要将其链接到以前的交易 current_net 作为它的 current_gross。
获取 current_gross 基本上是一个递归调用。这里我不能使用 PL SQL 函数,我可以编写一个快速递归函数来计算 current_gross。我需要这个任务的纯 PL/SQL 查询。 (可以使用内置的PL SQL函数)
【问题讨论】:
【参考方案1】:这是一个未经测试的近似答案(如果您为您的数据/结构提供了 create table
和 insert
语句,我会对其进行测试)。它假定您的事务表中没有分支(也就是说,link_trx_id
是唯一的)。基本上,我们使用递归连接来获取分组、父信息和顺序,然后使用分析函数来获取运行总计 (current_net
)。与其尝试获取以前的总数(我们可以这样做),不如简单地从current_net
中删除当前行的credit
和debit
似乎更有意义。
SELECT trx_id,
debit,
credit,
root_amt - cum_debit + cum_credit + debit - credit AS current_gross,
root_amt - cum_debit + cum_credit AS current_net
FROM (SELECT trx_id,
debit,
credit,
SUM(credit) OVER (PARTITION BY event_id ORDER BY lvl) AS cum_credit,
SUM(debit) OVER (PARTITION BY event_id ORDER BY lvl) AS cum_debit,
root_amt
FROM (SELECT trx_id,
debit,
credit,
LEVEL AS lvl,
CONNECT_BY_ROOT (gross_amount) AS root_amt,
CONNECT_BY_ROOT (event_id) AS event_id
FROM transaction t LEFT OUTER JOIN event e ON t.trx_id = e.transaction_id
CONNECT BY link_trx_id = PRIOR trx_id
START WITH link_trx_id IS NULL))
【讨论】:
不提供插入和创建表语句是我的错。谢谢 Jeff 已更正查询。【参考方案2】:使用 Allan 的查询,我添加了创建表和插入。 该查询的变量不匹配,因此我也更正了这些变量(debit_cum/credit_cum 与子查询中的 cum-credit/cum_debit 变量不匹配)。
create table event
(event_id number(9),
gross_amount number(9),
transaction_id number(9));
insert into event values (1,10,1);
insert into event values (2,12,5);
create table transaction
(trx_id number(9),
debit number(9),
credit number(9),
link_trx_id number(9)
);
insert into transaction values (1,4,0,null);
insert into transaction values (2,0,2,1);
insert into transaction values (3,0,1,2);
insert into transaction values (4,3,0,3);
insert into transaction values (5,0,5,null);
insert into transaction values (6,0,3,5);
SELECT trx_id,
debit,
credit,
root_amt - debit_cum + credit_cum + debit - credit AS current_gross,
root_amt - debit_cum + credit_cum AS current_net
FROM (SELECT trx_id,
debit,
credit,
SUM(credit) OVER (PARTITION BY event_id ORDER BY lvl) AS credit_cum,
SUM(debit) OVER (PARTITION BY event_id ORDER BY lvl) AS debit_cum,
root_amt,
event_id
FROM (SELECT trx_id,
debit,
credit,
LEVEL AS lvl,
CONNECT_BY_ROOT (gross_amount) AS root_amt,
CONNECT_BY_ROOT (event_id) AS event_id
FROM transaction t LEFT OUTER JOIN event e ON t.trx_id = e.transaction_id
CONNECT BY link_trx_id = PRIOR trx_id
START WITH link_trx_id IS NULL));
【讨论】:
Allan 应该获得正确查询的功劳。他做了所有艰苦的工作。以上是关于递归 PL SQL 查询帮助的主要内容,如果未能解决你的问题,请参考以下文章