在Oracle SQL中枢转多个日期范围

时间:2018-08-05 08:46:52

标签: sql oracle

这是我的输入数据:

MEMBER_ID EVENT     AMT_SBSDY   PLAN_ID         EFF_DT          TERM_DT
314450    SBSDY     0           NULL            01-SEP-2017     31-DEC-2017
314450    SBSDY     0           NULL            01-JAN-2018     30-JUN-2018
314450    SBSDY     40          NULL            01-JUL-2018     31-DEC-9999
314450    PLN       0           032             01-JAN-2018     31-DEC-9999

这是预期的输出:

MEMBER_ID EVENT_SBSDY   EVENT_PLAN  AMT_SBSDY   PLAN_ID         EFF_DT          TERM_DT
314450    SBSDY         NULL        0           NULL            01-SEP-2017     31-DEC-2017
314450    SBSDY         PLN         0           032             01-JAN-2018     30-JUN-2018
314450    SBSDY         PLN         40          032             01-JUL-2018     31-DEC-9999

成员是拥有两种不同事件(SBSDY-补贴金额和PLN-她的计划ID)的实体。

在第一个数据集中,该成员拥有第一个SBSDY事件,有效期从01-SEP-17到31-DEC-2017,补贴金额为$ 0。该成员有第二笔补贴事件,有效期从2018年01月01日至2018年6月30日(同样为$ 0),以及第三笔补贴事件,有效期为$ 40,有效日期为2018年01月01日至开放结束(当前有效)。

该成员还有一个PLN事件,从2018年1月01日至开放结束日期(当前有效)。该活动的日期范围与第二,第三次SUBSDY活动的日期范围重叠,因此从2018年1月1日到2018年6月1日,该会员的补贴金额为$ 0和计划ID 032,从2018年7月01日开始,该会员具有补贴金额为40美元,计划ID为032。

我需要在同一行而不是在不同的行中显示此详细信息(如源数据集中一样)。在日期范围为01-SEP-2017到2017年12月31日的输出数据集中,补贴金额为$ 0,并且Plan ID和Event_Plan为NULL(第一行)。对于2018年1月1日至2018年6月30日的日期范围,活动补贴= SBSDY(成员具有补贴金额),活动计划= PLN(成员具有该日期范围内的计划),计划ID为032,补贴= 0.输出数据集中的第三行显示了日期范围,从2018年7月01日到迄今为止,此行中的补贴金额为$ 40,计划ID为032。

我认为我需要做PIVOT,但是在这种情况下我仍然不清楚如何实现。

我的数据库是Oracle 12c第1版。

能帮我吗?

1 个答案:

答案 0 :(得分:1)

目前尚不清楚补贴日期和计划日期是否始终如您所显示的那样对齐,但是假设它们可以,您可以使用keep dense_rank获取最新的计划数据:

select member_id,
  event,
  max(case when event = 'PLN' then event end)
    over (partition by member_id order by eff_dt) as event_plan,
  amt_sbsdy,
  max(case when event = 'PLN' then plan_id end)
    over (partition by member_id order by eff_dt) as plan_id,
  eff_dt,
  term_dt
from your_table

,然后进行过滤以仅查看补贴事件:

-- CTE for your sample data
with your_table (member_id, event, amt_sbsdy, plan_id, eff_dt, term_dt) as (
            select 314450, 'SBSDY', 0, NULL, date '2017-09-01', date '2017-12-31' from dual
  union all select 314450, 'SBSDY', 0, NULL, date '2018-01-01', date '2018-06-30' from dual
  union all select 314450, 'SBSDY', 40, NULL, date '2018-01-07', date '2099-12-31' from dual
  union all select 314450, 'PLN', 0, '032', date '2018-01-01', date '2099-12-31' from dual
)
-- actual query
select member_id,
  event as event_sbsdy,
  event_plan,
  amt_sbsdy,
  plan_id,
  eff_dt,
  term_dt
from (
  select member_id,
    event,
    max(case when event = 'PLN' then event end)
      over (partition by member_id order by eff_dt) as event_plan,
    amt_sbsdy,
    max(case when event = 'PLN' then plan_id end)
      over (partition by member_id order by eff_dt) as plan_id,
    eff_dt,
    term_dt
  from your_table
)
where event = 'SBSDY'
order by member_id, eff_dt;

 MEMBER_ID EVENT_SBSDY EVENT_PLAN  AMT_SBSDY PLAN_ID EFF_DT     TERM_DT   
---------- ----------- ---------- ---------- ------- ---------- ----------
    314450 SBSDY                           0         2017-09-01 2017-12-31
    314450 SBSDY       PLN                 0 032     2018-01-01 2018-06-30
    314450 SBSDY       PLN                40 032     2018-01-07 2099-12-31