I would like to print in one row start date and end date for continous or overlaping date ranges.
here is the data
create table orders (
po varchar2(6),
st
Use window functions to see if there is any overlap with previous records. Then a cumulative sum to assign a "grouping" and aggregate.
I like to use a cumulative max for more generic overlaps:
select po, min(startdate), max(enddate)
from (select o.*,
sum(case when prev_enddate >= startdate then 0 else 1 end) over (partition by po order by startdate) as grouping
from (select o.*,
max(enddate) over (partition by po order by startdate range between unbounded preceding and '1' second preceding) as prev_enddate
from orders o
) o
) o
group by po, grouping;
In many cases, you can use lag()
instead of max()
:
select po, min(startdate), max(enddate)
from (select o.*,
sum(case when prev_enddate >= startdate then 0 else 1 end) over (partition by po order by startdate) as grouping
from (select o.*,
lag(enddate) over (partition by po order by startdate) as prev_enddate
from orders o
) o
) o
group by po, grouping;
This works so long as the previous row has the overlap, which is typically the case.
There is an elegant (and efficient) solution using the match_recognize
clause (which requires Oracle 12.1 or higher).
select po, startdate, enddate
from orders
match_recognize (
partition by po
order by startdate
measures first(startdate) as startdate, max(enddate) as enddate
pattern ( c* n )
define c as max(enddate) + 1 >= next(startdate)
);