计算与重叠日期范围相关联的值的总和

时间:2014-03-06 18:21:42

标签: postgresql date-range

我有一个简单的日期范围表,每个日期范围都有一个相关的每周小时数:

CREATE TABLE tmp_ranges (
  id SERIAL PRIMARY KEY,
  rng daterange,
  hrs_per_week INT
 );

我希望计算(即汇总)重叠/相交日期范围的每周小时数的一些值:

INSERT INTO tmp_ranges (rng, hrs_per_week) VALUES
   ('[2014-03-15, 2014-06-28]', 9),
   ('[2014-04-18, 2014-07-15]', 2),
   ('[2014-06-03, 2014-09-12]', 9),
   ('[2014-10-03, 2014-11-14]', 6);

图形化(希望这显示的不仅仅是它模糊不清),解决方案如下:

hrs/wk      T                                                 T`
  9         |  }-----|--------|-------->                      |
            |                                                 |
  2         |        }--------|--------|----->                |
            |                                                 |
  9         |                 }--------|------|---->          |
            |                                                 |
  6         |                                          }--->  |
            |                                                 |
 agg.hrs/wk     --9-- ---11--- ---20--- --11-- --9--    -6- 

最终日期范围与其他记录故意不连续,但仍会包含在最终记录集中...
很明显,解决方案需要从原始4中生成6条记录,我很确定答案涉及使用窗口函数,但我完全不知所措......

有没有办法实现这个目标?

非常感谢提前!

1 个答案:

答案 0 :(得分:3)

以下是我尝试解决此问题的方法:

select y,
     sum( hrs_per_week )
from tmp_ranges t
join(
  select daterange( x,
         lead(x) over (order by x) ) As y
  from (
    select lower( rng ) As x
    from tmp_ranges
    union 
    select upper( rng )
    from tmp_ranges
    order by x
  ) y
) y
on t.rng && y.y
group by y
order by y

演示:http://sqlfiddle.com/#!15/ef6cb/13

最里面的子查询使用union将所有边界日期收集到一个集合中,然后对它们进行排序 然后外部子查询使用lead函数从相邻日期构建新范围 最后,这些新范围将加入主查询中的源表,汇总,并计算sum


EDIT
最里面的查询中的order by子句是多余的,可以跳过,因为lead(x) over caluse按日期排序记录,而最内层子查询的结果集不必排序。