如何根据oracle中的条件在组中的行之间求和

问题描述 投票:1回答:2

我有一个数据集:

type              month       id1  id2  id3   value 
history           jan-17       1    2    3      10
future            jan-17       1    2    3      15
history           feb          1    2    3      12
history           march        1    2    3      11
future            march        1    2    3      14

我希望根据一些计算并基于type列的值来获得每个月的价值。

例如:输出应如下所示:

month    id1  id2  id3   value
JAN-17   1    2    3     15(future value of jan) + 0(as future value of feb is not present)+ 14(take the future value of march)
FEB-17   1    2    3     10(history value of jan)+14(take the future value of march)
MAR-17   1    2    3     10(history value of jan)+12(history value of feb)+11(history value of mar)

计算基于一年中每个月的季度数。 如果是一个季度的第一个月,则采用第一个月的未来值+第二个月的未来+第三个月的未来值

如果月份是一季度的第2个月,则取第1个月的历史值+第2个月的未来值+第3个月的未来值

如果月份是一个季度的第3个月,则取第1个月的历史值+第2个月的历史值+第3个月的未来值。

我已经尝试基于月id1id2id3对数据集进行分区,但它没有给我预期的结果。

sql oracle
2个回答
0
投票

您想要的输出与您进一步编写的规则相矛盾:

如果是一个季度的第一个月,则采用第一个月的未来值+第二个月的未来+第三个月的未来值

如果月份是一季度的第2个月,则取第1个月的历史值+第2个月的未来值+第3个月的未来值

如果月份是一个季度的第3个月,则取第1个月的历史值+第2个月的历史值+第3个月的未来值

我实现了这些规则,因为它们具有更清晰的逻辑并且更容易实现:

with t1 as (select 'history' type from dual union all select 'future' type from dual),
     d  as (select add_months(date '2017-01-01', rownum - 1) month, 1 id1, 2 id2, 3 id3 from dual connect by level < 4),
     t2 as (select * from t1, d),
     source (type, month, id1, id2, id3, value) as (
            select 'history', 'jan-17', 1, 2, 3, 10 from dual union all
            select 'future',  'jan-17', 1, 2, 3, 15 from dual union all
            select 'history', 'feb-17', 1, 2, 3, 12 from dual union all
            select 'history', 'mar-17', 1, 2, 3, 11 from dual union all
            select 'future',  'mar-17', 1, 2, 3, 14 from dual)
select to_char(month, 'mon-yy') mon, id1, id2, id3, history, future,
       sum(history) over (partition by to_char(month, 'Q') order by month) - history +
       sum(future) over (partition by to_char(month, 'Q') order by month desc) value
  from (select t2.type, t2.month, nvl(s.id1, t2.id1) id1, nvl(s.id2, t2.id2) id2, nvl(s.id3, t2.id3) id3, nvl(value, 0) value
          from t2 left join source s on s.type = t2.type and s.month = to_char(t2.month, 'mon-yy'))
 pivot (sum(value) for type in ('history' history, 'future' future))
order by month

这个怎么运作:

  • 子查询t1t2d用于生成月份和类型的完整列表
  • 然后将它们与源数据连接起来并制作一个支点
  • 计算不同方向的“期货”和“历史”的运行总和
  • 然后将这些运行总和加在一起减去当前历史值,这正是我们所需要的: MON ID1 ID2 ID3 HISTORY FUTURE VALUE ------------ ---------- ---------- ---------- ---------- ---------- ---------- jan-17 1 2 3 10 15 29 feb-17 1 2 3 12 0 24 mar-17 1 2 3 11 14 36

该解决方案可以应用于任何时间段,将分别计算每个季度的数据。


0
投票

我不知道如何处理id1,id2,id3所以我选择忽略它,更好地解释它的相应逻辑。对于历史,特定月份的未来,它是否总是相同的价值?

with 
x as
    (select 'hist' type, To_Date('JAN-2017','MON-YYYY') ym , 10 value from dual union all
    select 'future' type, To_Date('JAN-2017','MON-YYYY'), 15 value from dual union all
    select 'future' type, To_Date('FEB-2017','MON-YYYY'), 1 value from dual),
y as
    (select * from x Pivot(Sum(Value) For Type in ('hist' as h,'future' as f))),
    /* Pivot for easy lag,lead query instead of working with rows..*/
z as
    (
        select ym,sum(h) H,sum(f) F from (
            Select y.ym,y.H,y.F from y
            union all
            select add_months(to_Date('01-JAN-2017','DD-MON-YYYY'),rownum-1) ym, 0 H, 0 F 
            from dual connect by rownum <=3 /* depends on how many months you are querying... 
            so this dual adds the corresponding missing 0 records...*/
        ) group by ym
    )
select 
ym,
Case
    When MOD(Extract(Month from YM),3) = 1
    Then F + Lead(F,1) Over(Order by ym) + Lead(F,2) Over(Order by ym)
    When MOD(Extract(Month from YM),3) = 2
    Then Lag(H,1) Over(Order by ym) + F + Lead(F,1) Over(Order by ym)
    When MOD(Extract(Month from YM),3) = 3
    Then Lag(H,2) Over(Order by ym) + Lag(H,1) Over(Order by ym) + F
End Required_Value
from z
© www.soinside.com 2019 - 2024. All rights reserved.