Вы включаете дату окончания в диапазон дат. Это работает, только если дата окончания считается самим диапазоном дат, начиная с полуночи до полуночи. Поскольку «даты» Oracle включают компонент времени, я настоятельно рекомендую рассматривать «дату» Oracle как точку во времени. В этом случае гораздо лучше сказать, что конечное время и дата не включены в диапазон. В этом подходе применяется стандарт SQL «Временная достоверность».
В качестве бонуса использование «исключительных» дат окончания облегчает подобные проблемы.
Я работаю над этим, добавляя 1 к дате окончания вначало запроса и вычитание 1 перед завершением запроса. См. https://stewashton.wordpress.com/2018/11/26/ranges-with-nulls-05-segments/ для объяснения и того, что делать с NULL в диапазонах дат.
create table t(START_DATE, END_DATE) as
select to_date('01-SEP-19','dd-mon-yy'), to_date('04-OCT-19','dd-mon-yy') from dual union all
select to_date('01-OCT-19','dd-mon-yy'), to_date('30-OCT-19','dd-mon-yy') from dual union all
select to_date('05-OCT-19','dd-mon-yy'), to_date('20-OCT-19','dd-mon-yy') from dual union all
select to_date('31-OCT-19','dd-mon-yy'), to_date('15-NOV-19','dd-mon-yy') from dual;
with unpivoted as (
select * from (
select start_date, end_date + 1 end_date from t
)
unpivot(start_date for seg_start in(start_date as 1, end_date as -1))
)
select start_date, end_date - 1 end_date, NUM_SEGS
from (
select u.*,
lead(start_date) over(order by start_date) end_date,
sum(seg_start) over(order by start_date) num_segs
from unpivoted u
)
where num_segs > 0 and start_date < end_date;
START_DATE END_DATE NUM_SEGS
---------- ---------- ----------
2019-09-01 2019-09-30 1
2019-10-01 2019-10-04 2
2019-10-05 2019-10-20 2
2019-10-21 2019-10-30 1
2019-10-31 2019-11-15 1
С наилучшими пожеланиями, Stew Ashton