Oracle 累积或增量减法

问题描述 投票:0回答:3

我的表结构和数据-

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
。但无法实现。

请帮忙。

oracle group-by cumulative-sum
3个回答
1
投票

您可以使用

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

小提琴


0
投票

仅供记录,虽然有点晚了,您可以使用 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
*/

0
投票

您可以使用聚合来实现此目的:

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
    感兴趣的领域

小提琴:http://sqlfiddle.com/#!4/f0d53/13

© www.soinside.com 2019 - 2024. All rights reserved.