I have the following data set with Account number and dates
Account Start Date End_Date
---------------------------------------
1111222333 05/01/2016 15/02/2016
1111222333 29/01/2016 04/04/2016
1111222333 20/03/2016 13/05/2016
1111222333 26/04/2016 06/06/2016
1111222333 05/05/2016 06/06/2016
1111222333 13/09/2016 10/10/2016
1111222333 14/10/2016 15/12/2016
1111222333 09/08/2017 25/08/2017
1111222333 25/10/2017 10/11/2017
1111222333 02/11/2017 05/01/2018
most of the date ranges are overlapping and I require the min start date and max end date from the overlapping range, so the output should look like this:
Account Start Date End_Date
----------------------------------
1111222333 05/01/2016 06/06/2016
1111222333 13/09/2016 10/10/2016
1111222333 14/10/2016 15/12/2016
1111222333 09/08/2017 25/08/2017
1111222333 25/10/2017 05/01/2018
I am quite a novice user, and realised the above is well beyond my current capabilities so over to you experts :)
This is a gaps-and-islands problem. One way to solve it is to get a list of all dates and keep track of the number of "records" that is applies to. Then, some window functions and aggregation solve the problem.
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;
Here is a rextester (using Postgres).
Here is the code in the rextester:
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;
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.