我对Oracle分析功能非常熟悉,但这个让我很难过。如果有一个明显的解决方案,我会踢自己:)
我有一个表,JOURNAL,它在另一个表上记录插入,更新和删除。
它是日记的表是BOND_PAYMENTS,它代表PAYMENTS和BONDS之间的链接;它存储从特定付款(由PAYMENT_ID标识)分配给特定债券(由BOND_NUMBER标识)的金额(AMOUNT)。此外,它还记录了分配给(BOP_DOMAIN)的债券的哪个方面,可能是“BON”,“PET”或其他一些代码。 BOND_PAYMENTS表有一个代理键(BOP_ID)。
因此,对于每个BOP_ID,我的日志表通常会有一条或多条记录 - 首先是一个INSert,后面可能是一些UPD,后面可能是一个DELete。
这是JOURNAL表:
CREATE TABLE JOURNAL
( JN_DATE_TIME DATE NOT NULL,
JN_OPERATION VARCHAR2(3) NOT NULL,
BOP_ID NUMBER(9) NOT NULL,
PAYMENT_ID NUMBER(9) NOT NULL,
BOND_NUMBER VARCHAR2(20) NOT NULL,
BOP_DOMAIN VARCHAR2(10) NOT NULL,
AMOUNT NUMBER(14,2) NOT NULL
);
以下是一些示例数据:
INSERT INTO JOURNAL VALUES (TO_DATE('01/01/2010','DD/MM/YYYY'),'INS',1242043,1003700,'9995/10','BON',1800);
INSERT INTO JOURNAL VALUES (TO_DATE('03/01/2010','DD/MM/YYYY'),'INS',1242046,1003700,'9998/10','BON',1700);
INSERT INTO JOURNAL VALUES (TO_DATE('04/01/2010','DD/MM/YYYY'),'INS',1242048,1003700,'9999/10','BON',1800);
INSERT INTO JOURNAL VALUES (TO_DATE('05/01/2010','DD/MM/YYYY'),'INS',1242052,1003700,'10003/10','BON',1600);
INSERT INTO JOURNAL VALUES (TO_DATE('08/01/2010','DD/MM/YYYY'),'INS',1242058,1003700,'9998/10','BON',100);
INSERT INTO JOURNAL VALUES (TO_DATE('09/01/2010','DD/MM/YYYY'),'UPD',1242058,1003700,'9998/10','PET',100);
INSERT INTO JOURNAL VALUES (TO_DATE('01/01/2010','DD/MM/YYYY'),'INS',2242043,1003701,'8995/10','BON',1800);
INSERT INTO JOURNAL VALUES (TO_DATE('02/01/2010','DD/MM/YYYY'),'INS',2242046,1003701,'8998/10','BON',1700);
INSERT INTO JOURNAL VALUES (TO_DATE('03/01/2010','DD/MM/YYYY'),'INS',2242048,1003701,'8999/10','BON',1800);
INSERT INTO JOURNAL VALUES (TO_DATE('04/01/2010','DD/MM/YYYY'),'INS',2242058,1003701,'8998/10','BON',100);
INSERT INTO JOURNAL VALUES (TO_DATE('05/01/2010','DD/MM/YYYY'),'UPD',2242046,1003701,'8998/10','BON',1500);
INSERT INTO JOURNAL VALUES (TO_DATE('06/01/2010','DD/MM/YYYY'),'INS',2242052,1003701,'9003/10','BON',1600);
INSERT INTO JOURNAL VALUES (TO_DATE('07/01/2010','DD/MM/YYYY'),'UPD',2242058,1003701,'8998/10','PET',200);
现在,我需要从这个日志表中提取一整套数据,但格式略有不同。主要要求是我们不希望日志表再次记录BOP_DOMAIN - 这不是必需的。
我需要为每个BOND_PAYMENT记录生成总金额的历史记录。我无法使用BOND_PAYMENT表本身,因为它只显示每条记录的最新状态。我需要从期刊中获取这些信息。
我不能只采用SUM(amount) over(partition by payment_id, bond_number)
因为个别BOP_ID可能会多次更新;因此,在任何一个时刻,只应使用为该BOP_ID记录的最新金额。
鉴于以上样本数据,以下是我希望产生的内容:
SELECT jn_date_time,
jn_operation,
bop_id,
payment_id,
bond_number,
bop_domain,
amount,
? as running_total
FROM JOURNAL
ORDER BY jn_date_time;
这里我在左边再现了样本数据,用于两次样本付款。在右边我有“Running Total”,这是预期的输出。它旁边(红色)是计算每一行的总计的逻辑。
“正在运行的总计”是在日记帐分录的时间点,PAYMENT_ID和BOND_NUMBER组合的总金额的快照。请记住,特定的BOP_ID可能会多次更新;总金额必须只考虑该BOP_ID的最新记录。
任何可行的解决方案都是可以接受的,但我怀疑分析函数(或分析函数的组合)将是解决此问题的最佳方法。
答案 0 :(得分:6)
试试这个
WITH inner AS
(SELECT jn_date_time,
jn_operation,
bop_id,
payment_id,
bond_number,
bop_domain,
amount,
amount - coalesce(lag(amount) over (partition by bop_id order by jn_date_time), 0)
as delta_bop_amount
FROM JOURNAL)
SELECT inner.*,
sum(delta_bop_amount)
over (partition by payment_id, bond_number order by jn_date_time) as running_total
FROM inner
ORDER BY bond_number, payment_id
这将为您的示例返回相同的答案。
您需要两次传递 - 内部查询中的分析函数计算每条记录更改每个BOP_ID的总数。 INS是直接添加,UPD必须减去最新值并添加新值。
然后第二遍通过债券/付款进行总计。
我假设您希望将债券/付款视为运行金额的自然关键,并且任何债券/付款组合可能有多个BOP_ID。
答案 1 :(得分:0)
{{1}}
此解决方案提供了您对上述问题所期望的确切答案,并且在单个表格中也是如此:)。
我刚刚使用滞后分析函数来获取每个bond_number / payment_id组合的最近金额值,然后将最近的金额值添加到获得运行总额的金额...简单!!! ..不是吗:)