我有以下数据集,帐号和日期
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
大多数日期范围都是重叠的,我需要重叠范围内的最小开始日期和最大结束日期,因此输出应如下所示:
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
我是一个相当新手的用户,并意识到上述内容远远超出了我目前的能力,所以对你们专家来说:)
答案 0 :(得分:0)
这是一个缺口和岛屿问题。解决它的一种方法是获取所有日期的列表并跟踪适用的“记录”的数量。然后,一些窗口函数和聚合解决了这个问题。
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)。
以下是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;