Это довольно сложно. Идея состоит в том, чтобы «разворачивать» даты и следить за тем, чтобы type
входил или выходил каждый день. Затем вы можете использовать накопительные суммы, чтобы отслеживать фактический тип.
Итак:
with t as (
select date '2001-01-01' as sdate, date '2001-12-31' as edate, 'Working' as type from dual union all
select date '2001-05-01' as sdate, date '2001-05-12' as edate, 'holidays' from dual
),
d as (
select sdate as dte, type, 1 as flag from t union all
select edate + 1, type, -1 as flag from t
)
select d.dte, lead(dte) over (order by dte) - 1 as enddte,
(case when flag = -1 then lag(type) over (partition by grp order by dte) else type end) as type
from (select d.*, sum(flag) over (order by dte) as grp
from d
) d
order by dte;
Здесь - это дБ <> скрипка.
EDIT:
Здесь - улучшенная версия:
with t as (
select date '2001-01-01' as sdate, date '2001-12-31' as edate, 'Working' as type from dual union all
select date '2001-05-01' as sdate, date '2001-05-12' as edate, 'holidays' from dual union all
select date '2001-07-01' as sdate, date '2001-08-12' as edate, 'holidays' from dual
),
d as (
select sdate as dte from t union all
select edate + 1 from t
)
select d.dte, d.enddte,
(select max(t2.type) keep (dense_rank first order by t2.sdate desc)
from t t2
where t2.sdate <= d.dte and t2.edate >= d.enddte
) as type
from (select d.*, lead(dte) over (order by dte) - 1 as enddte
from d
) d
where dte <= enddte
order by d.dte
Этот подход просто получает отдельные периоды (разбивая первоначальные периоды). Затем для каждого периода он находит type
, действительный в течение этого периода. Это самая последняя запись, охватывающая весь период.
Обратите внимание, что поскольку даты являются "смежными", частичное покрытие периодов отсутствует.