2014-03-06 100 views
1

我有日期的一個簡單的表範圍各自具有每週小時一個關聯的編號:計算總和範圍

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條記錄,我很確定答案涉及使用窗口功能,但我完全處於虧損狀態......

有沒有辦法做到這一點?

非常感謝提前!

回答

2

這是我試圖解決這個問題:

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


編輯
在最內層查詢的order by條款是多餘的,可以跳過,因爲lead(x) over caluse訂單記錄的日期,並從最裏面的子查詢結果集不必進行排序。

+0

這是一個夢幻般的解決方案,謝謝(實際上,我最誠摯的謝意(!),今晚我可以入睡......)。我很想知道是否有其他方法/技巧可以用來達到同樣的效果。 – user908094