我的表结构和数据-
CREATE TABLE T_PTS_TEST
(
CITY_ID NUMBER,
MNTH DATE,
EARNS NUMBER,
BURNS NUMBER
);
insert into T_PTS_TEST values( 125600, TO_DATE('2023-May-31', 'YYYY-Month-DD'), 600, -400 );
insert into T_PTS_TEST values( 125600, TO_DATE('2023-June-30', 'YYYY-Month-DD'), 400, -300 );
insert into T_PTS_TEST values( 125600, TO_DATE('2023-July-31', 'YYYY-Month-DD'), 800, -600 );
insert into T_PTS_TEST values( 125600, TO_DATE('2023-August-31', 'YYYY-Month-DD'), 500, 0 );
insert into T_PTS_TEST values( 125600, TO_DATE('2023-September-30', 'YYYY-Month-DD'), 900, 0 );
桌子-
CITY_ID | 一个月 | 赚取 | 烧伤 |
---|---|---|---|
125600 | 23 年 5 月 31 日 | 600 | -400 |
125600 | 23 年 6 月 30 日 | 400 | -300 |
125600 | 23 年 7 月 31 日 | 800 | -600 |
125600 | 23 年 8 月 31 日 | 500 | 0 |
125600 | 23 年 9 月 30 日 | 900 | 0 |
因此,这个特定城市从 5 月到 9 月的总燃烧量是 -1300,即
select city_id, sum(burns) from T_PTS_TEST group by city_id
我想从每次收入中累计减去这个total_burns,如下-
Total Deductions = -1300
Cumulative Deductions
May - 600 -1300 = -700
June - 400 -700 = -300
July - 800 -300 = 500
Aug - 500
Sep - 900
查询输出应如下所示 -
CITY_ID | 一个月 | 赚取 | NET_PTS |
---|---|---|---|
125600 | 23 年 5 月 31 日 | 600 | -700 |
125600 | 23 年 6 月 30 日 | 400 | -300 |
125600 | 23 年 7 月 31 日 | 800 | 500 |
125600 | 23 年 8 月 31 日 | 500 | 500 |
125600 | 23 年 9 月 30 日 | 900 | 900 |
我可以通过在 PL/SQL 块或函数内循环来实现上述目的,但如何使用 select 语句执行相同的操作? 我尝试使用不同的方式,例如
sum(..) over
和lag
。但无法实现。
请帮忙。
您可以使用
SUM
分析函数查找每月累计收入和总消耗,然后使用 LEAST
函数查找总收入和当月收入中的较小者:
SELECT city_id,
mnth,
earns,
LEAST(
SUM(earns) OVER (PARTITION BY city_id ORDER BY mnth)
+ SUM(burns) OVER (),
earns
) AS total
FROM t_pts_test t
对于样本数据,输出:
CITY_ID | 一个月 | 赚取 | 总计 |
---|---|---|---|
125600 | 2023-05-31 00:00:00 | 600 | -700 |
125600 | 2023-06-30 00:00:00 | 400 | -300 |
125600 | 2023-07-31 00:00:00 | 800 | 500 |
125600 | 2023-08-31 00:00:00 | 500 | 500 |
125600 | 2023-09-30 00:00:00 | 900 | 900 |
仅供记录,虽然有点晚了,您可以使用 MODEL 子句来获取结果:
Select CITY_ID, MNTH, EARNS, NET_PTS
From ( Select CITY_ID, To_Char(MNTH, 'yyyy-mm') "MNTH", EARNS, BURNS,
0 "NET_PTS"
From T_PTS_TEST
)
MODEL Partition By ( CITY_ID )
Dimension By ( MNTH )
Measures ( EARNS, BURNS, NET_PTS )
RULES ( NET_PTS[ANY] = Case When BURNS[CV()] != 0 Then Sum(EARNS)[MNTH <= CV()] + Sum(BURNS)[MNTH Is Not Null] Else EARNS[CV()] End )
/* R e s u l t :
CITY_ID MNTH EARNS NET_PTS
---------- ------- ---------- ----------
125600 2023-05 600 -700
125600 2023-06 400 -300
125600 2023-07 800 500
125600 2023-08 500 500
125600 2023-09 900 900
*/
您可以使用聚合来实现此目的:
select t.CITY_ID, T_PTS_TEST.MNTH, T_PTS_TEST.EARNS, sum(t2.EARNS) + t.TOTAL as NET_PTS
from T_PTS_TEST
join (
select CITY_ID, sum(BURNS) as TOTAL
from T_PTS_TEST
group by CITY_ID
) t
on T_PTS_TEST.CITY_ID = t.CITY_ID
join (
select CITY_ID, MNTH, EARNS
from T_PTS_TEST
group by CITY_ID, MNTH, EARNS
) t2
on T_PTS_TEST.CITY_ID = t2.CITY_ID and
T_PTS_TEST.MNTH >= t2.MNTH
group by t.CITY_ID, T_PTS_TEST.MNTH, T_PTS_TEST.EARNS, t.TOTAL
order by t.CITY_ID, T_PTS_TEST.MNTH;
说明:
t
,按 CITY_ID
分组,因此我们不会混淆城市EARNS
“到目前为止”投射到 t2
t
与 CITY_ID
相连,t2
与 CITY_ID
相连且 MNTH
不晚于当前group by
我们想要聚合的字段select
感兴趣的领域