简体   繁体   中英

Hive SQL - Getting Min and Max dates for Overlapping Dates

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM