合并 postgres 中的日期范围以消除重叠
Coalescing date ranges in postgres to eliminate overlaps
如果我有一个 postgres table a:
member | start | end
---------+------------+------------
1 | 2015-01-01 | 2015-05-01
---------+------------+------------
1 | 2015-03-01 | 2015-06-01
---------+------------+------------
2 | 2015-01-01 | 2015-05-01
---------+------------+------------
2 | 2015-06-01 | 2015-08-01
我将如何合并日期以消除像这样的重叠范围:
member | start | end
---------+------------+------------
1 | 2015-01-01 | 2015-06-01
---------+------------+------------
2 | 2015-01-01 | 2015-05-01
---------+------------+------------
2 | 2015-06-01 | 2015-08-01
在 chop
中,CTE 原始范围 "chopped" 变成更小的、不相交(但可能相邻)的范围。它们由原始范围的所有端点构成,包括开始和结束。
主要select工作如下(从里到外读):
- 当范围与前一个范围相邻时,范围的相邻标志为零(假设范围按其开始日期排序)。
- 相邻标志的累积和给我们一个分组值:所有相邻范围将具有相同的总和。
- 最外面的块只是计算相邻范围组的边界值。
window functions的黑魔法...
with chop as (
select member,
pt as start,
lead(pt) over (partition by member order by pt) finish,
(
select count(*)
from a
where b.member = a.member
and b.pt >= a.start
and b.pt < a.finish
) need_it
from (
select member, start pt from a
union
select member, finish pt from a
) b
)
-- 3
select member,
min(start),
max(finish)
from (
-- 2
select member,
start,
finish,
sum(adjacent) over (partition by member order by start) grp
from (
-- 1
select member,
start,
finish,
case
when start <= lag(finish) over (partition by member order by start)
then 0
else 1
end adjacent
from chop
where need_it > 0
) t
) q
group by member,
grp
order by member,
min(start);
我将 end
重命名为 finish
因为 end
是关键字。
如果我有一个 postgres table a:
member | start | end
---------+------------+------------
1 | 2015-01-01 | 2015-05-01
---------+------------+------------
1 | 2015-03-01 | 2015-06-01
---------+------------+------------
2 | 2015-01-01 | 2015-05-01
---------+------------+------------
2 | 2015-06-01 | 2015-08-01
我将如何合并日期以消除像这样的重叠范围:
member | start | end
---------+------------+------------
1 | 2015-01-01 | 2015-06-01
---------+------------+------------
2 | 2015-01-01 | 2015-05-01
---------+------------+------------
2 | 2015-06-01 | 2015-08-01
在 chop
中,CTE 原始范围 "chopped" 变成更小的、不相交(但可能相邻)的范围。它们由原始范围的所有端点构成,包括开始和结束。
主要select工作如下(从里到外读):
- 当范围与前一个范围相邻时,范围的相邻标志为零(假设范围按其开始日期排序)。
- 相邻标志的累积和给我们一个分组值:所有相邻范围将具有相同的总和。
- 最外面的块只是计算相邻范围组的边界值。
window functions的黑魔法...
with chop as (
select member,
pt as start,
lead(pt) over (partition by member order by pt) finish,
(
select count(*)
from a
where b.member = a.member
and b.pt >= a.start
and b.pt < a.finish
) need_it
from (
select member, start pt from a
union
select member, finish pt from a
) b
)
-- 3
select member,
min(start),
max(finish)
from (
-- 2
select member,
start,
finish,
sum(adjacent) over (partition by member order by start) grp
from (
-- 1
select member,
start,
finish,
case
when start <= lag(finish) over (partition by member order by start)
then 0
else 1
end adjacent
from chop
where need_it > 0
) t
) q
group by member,
grp
order by member,
min(start);
我将 end
重命名为 finish
因为 end
是关键字。