I have following data :
ID Begin_Dt End_DT
101 201205 201208
101 201301 201309
101 201401 201502
101 201701 201801
Now if begin_DT is <= 9 months from the previous instance end date than I need to override the end_dt or previous row wiht end_dt of next row. I need to repeat it untill difference is <= 9
Lets calculate difference >>
Row_num ID Begin_Dt End_DT Diff
1 101 201205 201208 NA
2 101 201301 201309 5
3 101 201401 201502 4
4 101 201701 201801 23
difference in row 2 and row 3 is <=9 hence solution should be
ID Begin_Dt End_DT Flag_corr
101 201205 201502 1
101 201301 201502 1
101 201401 201502 0
101 201701 201801 0
Try to use LAG funcion.
with q0 as (
-- convert numbers to date and calculate lag
select to_date(begin_dt,'yyyymm') as begin_dt,
to_date(end_dt,'yyyymm') as end_dt,
lag(to_date(end_dt,'yyyymm'),1) over(order by begin_dt) as end_dt_prev
from dt
)
-- calculate difs and create flag
select q0.*,
months_between(end_dt,end_dt_prev) as diff,
case when months_between(end_dt,end_dt_prev) > 9 then 1 else 0 end as flag
from q0
This is a form of gaps-and-islands problem, with the islands defined by the 9 month gap. A cumulative sum of starts (based on the lag) defines the groups; then one more step gets the maximum date:
select t.*,
max(end_dt) over (partition by id, grp) as new_end_dt
from (select t.*,
sum(case when prev_end_dt >= add_months(begin_dt, -9) then 0 else 1 end) over (partition by id order by end_dt) as grp
from (select t.*,
lag(end_dt) over (partition by id order by end_dt) as prev_end_dt
from t
) t
) t
You say "I need to repeat it until difference is <= 9". To me that means you want to group together rows as long as the total of their gaps is not more than 9 months. I'm not sure the other answers try to do that.
You should always say what version of the Oracle database you are using. If you are using 12c or later, you can use the marvelous MATCH_RECOGNIZE clause:
with data(ID,Begin_Dt,End_DT ) as (
select 101, to_date('201205', 'yyyymm'), to_date('201208', 'yyyymm') from dual union all
select 101, to_date('201301', 'yyyymm'), to_date('201309', 'yyyymm') from dual union all
select 101, to_date('201401', 'yyyymm'), to_date('201502', 'yyyymm') from dual union all
select 101, to_date('201701', 'yyyymm'), to_date('201801', 'yyyymm') from dual
)
select * from (
select d.*,
months_between(
begin_dt,
lag(end_dt,1,begin_dt) over(partition by id order by end_dt)
) mon
from data d
)
match_recognize(
partition by id order by begin_dt
measures final last(end_dt) new_end_dt
all rows per match
pattern(a b*)
define b as sum(mon) <= 9
);
ID BEGIN_DT NEW_END_DT END_DT MON
101 2012-05-01 00:00 2015-02-01 00:00 2012-08-01 00:00 0
101 2013-01-01 00:00 2015-02-01 00:00 2013-09-01 00:00 5
101 2014-01-01 00:00 2015-02-01 00:00 2015-02-01 00:00 4
101 2017-01-01 00:00 2018-01-01 00:00 2018-01-01 00:00 23
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.