在postgres中合并日期范围以消除重叠 [英] Coalescing date ranges in postgres to eliminate overlaps

查看:423
本文介绍了在postgres中合并日期范围以消除重叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个postgres表a:

If I have a 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

我如何合并日期以消除类似的重叠范围:

How would I coalesce dates to eliminate overlapping ranges like this:

  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原始范围切成较小的,不相交(但可能相邻)的范围。它们是从原始范围的所有端点(从起点到终点)构造的。

In the chop CTE original ranges are "chopped" into smaller, non-intersecting (but possibly adjacent) ranges. They are constructed from all the end points of the original ranges, both start and finish.

主要选择方式如下(从内而外读取):

Main select works as follows (read it from the inside out):


  1. 与先前的范围相邻时,该范围的相邻标志为零(假设范围按其开始日期排序)。

  2. 相邻标志的累加总和为我们提供一个分组值:所有相邻范围将具有相同的总和。

  3. 最外面的块仅计算相邻组的边界值

窗口函数 ...

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 重命名为完成,因为 end 是关键字。

I renamed end to finish because end is a keyword.

这篇关于在postgres中合并日期范围以消除重叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆