我有一个简单的日期范围表,每个日期范围都有一个相关的每周小时数:
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条记录,我很确定答案涉及使用窗口函数,但我完全不知所措......
有没有办法实现这个目标?
非常感谢提前!
答案 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按日期排序记录,而最内层子查询的结果集不必排序。