Это проблема пробелов и островков. Один из способов решить эту проблему - получить список всех дат и отследить количество «записей», к которым оно относится. Затем некоторые оконные функции и агрегация решают проблему.
with d as (
select account, startdate as dte, 1 as inc
from t
union all
select account, enddate as dte, -1 as inc
from t
),
ds as ( -- accumulate "inc". Rows with "0" are ends of islands
select account, dte, sum(running_inc) over (partition by account order by dte) as running_inc
from (select account, dte, sum(inc) as running_inc
from d
group by account, dte
) d
),
g as ( -- assign group
select account, dte,
sum(case when running_inc = 0 then 1 else 0 end) over (partition by account order by dte desc) as grp
from ds
)
select account, min(dte) as start_date, max(dte) as end_dte
from g
group by account, grp;
Вот rextester (с использованием Postgres).
Вот код в тестере:
with t(account, startdate, enddate) as (
select 1111222333, '2016-01-05'::date, '2016-02-15'::date union all
select 1111222333, '2016-01-29'::date, '2016-04-04'::date union all
select 1111222333, '2016-03-20'::date, '2016-05-13'::date union all
select 1111222333, '2016-04-26'::date, '2016-06-06'::date union all
select 1111222333, '2016-05-05'::date, '2016-06-06'::date union all
select 1111222333, '2016-09-13'::date, '2016-10-10'::date union all
select 1111222333, '2016-10-14'::date, '2016-12-15'::date union all
select 1111222333, '2017-08-09'::date, '2017-08-25'::date union all
select 1111222333, '2017-10-25'::date, '2017-11-10'::date union all
select 1111222333, '2017-11-02'::date, '2018-01-05'::date
),
d as (
select account, startdate as dte, 1 as inc
from t
union all
select account, enddate as dte, -1 as inc
from t
),
ds as ( -- accumulate "inc". Rows with "0" are ends of islands
select account, dte, sum(running_inc) over (partition by account order by dte) as running_inc
from (select account, dte, sum(inc) as running_inc
from d
group by account, dte
) d
),
g as ( -- assign group
select account, dte,
sum(case when running_inc = 0 then 1 else 0 end) over (partition by account order by dte desc) as grp
from ds
)
select account, min(dte) as start_date, max(dte) as end_dte
from g
group by account, grp;