2015-11-03 117 views
0

我有簡單的表,其中有start_dateend_date列。這些日期值可能重疊日期的總計範圍沒有計算mysql中的重疊

id start_date end_date 
1  2011-01-01 2012-04-01 
2  2012-05-01 2013-10-01 
3  2013-09-01 2014-09-01 
4  2013-10-01 2014-08-01 
5  2013-12-01 2014-11-01 
6  2013-09-01 2014-09-01 
7  2015-01-01 2015-11-01 

問題是要在幾個月內找到總和。例如: id: 2,3,4,5,6重疊,所以想法是採取MAX end_date2,3,4,5,6 MIN start_date並添加1的時間差,以及7

此時:我已經找到了如何估算個月的時間差:

PERIOD_DIFF(DATE_FORMAT(end_date, '%Y%m') , DATE_FORMAT(start_date, '%Y%m')) 

我知道這裏的想法是:

  1. 瞭解兩個日期是否重疊與否。如果是,則合併日期相應的日期(如果需要,調整結束日期和開始日期)
  2. 循環遍歷所有日期,估計日期差異以月爲單位,總和並返回最終結果。

我一直在尋找類似的問題,無法解決和問題,會很好,如果你能幫助我。我知道可以使用一些編程語言並在那裏估計它,但是想用MySQL查詢來編寫它。

感謝

回答

1

這是忙碌的任何東西,但應該讓你什麼您需要:

SELECT SUM(PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM a.end_date), EXTRACT(YEAR_MONTH FROM a.start_date))) months 
    FROM (
    SELECT MIN(g.start_date) start_date, MAX(g.end_date) end_date 
     FROM (
     SELECT @group_id := @group_id + (@end_date IS NULL OR o.start_date > @end_date) group_id, 
       start_date, 
       @end_date := DATE(CASE 
       WHEN (@end_date IS NULL OR o.start_date > @end_date) THEN o.end_date 
       ELSE GREATEST(o.end_date, @end_date) 
       END) end_date 
      FROM overlap o 
      JOIN (SELECT @group_id := 0, @end_date := NULL) init 
     ORDER BY o.start_date ASC 
      ) g 
    GROUP BY g.group_id 
     ) a 

最內層的查詢將您的週期在重疊的組中組合在一起,並在適當的位置延伸end_date。 end_date會彎曲,因爲我認爲可能會有一段時間完全被前一個封閉。

下一個包裝查詢從每個組中提取完整範圍。

外部查詢爲每個組總計完整月份差異。 PERIOD_DIFF將所有組差異向下舍入爲最接近的整個月份。

不幸的是,我無法測試這個,因爲SQLFiddle已經死了我。

+0

謝謝你的回答,我已經在我的測試集上運行了你的代碼,它返回了-55,但它應該是55,但我在Stackoverflow上採取了一些其他的答案,並構建了我自己的一個,並在這裏回答了它: http://stackoverflow.com/a/33507876/1206495 – Askhat

+0

啊,雙重檢查文檔,period_diff參數需要反轉。我已經更新了答案。必須承認,我很困惑你的答案..當我測試它時它返回0。 – Arth

+0

我已經測試了你的答案,它正在工作,我認爲你的答案比我的結構更加結構化。所以我會接受它。感謝您的貢獻 – Askhat

0

如果你需要大量的記錄,包括重疊的總時間,然後簡單地總結每個記錄期間的差異:

SELECT SUM(PERIOD_DIFF(DATE_FORMAT(end_date, '%Y%m') , DATE_FORMAT(start_date, '%Y%m'))) AS total_periods 
FROM table WHERE ... 
+0

是的,但我需要排除重疊。有任何想法嗎? – Askhat

+0

那麼max(end_date) - min(start_date)解決方案有什麼問題? – Shadow

0

我做到了我自己的方式在這裏#2檢查其他的答案,它應該工作:

select sum(months) 
from (select t.*, 
     @time := if(@sum = 0, 0, period_diff(date_format(start_date, '%Y%m'), date_format(@prevtime, '%Y%m'))) as months, 
     @prevtime := start_date, 
     @sum := @sum + isstart 
    from ((select start_date, 1 as isstart 
     from position t 
     ) union all 
     (select end_date, -1 
     from position t 
     ) 
     ) t cross join 
     (select @sum := 0, @time := 0, @prevtime := 0) vars 
    order by 1, 2 
) t