2015-04-04 18 views
-1

我有如下表:如何使用Postgres只使用一條語句來返回兩列之間的一系列日期?

create_table "activities", force: :cascade do |t| 
    ... 
    t.date  "start_date",             null: false 
    t.time  "start_time",             null: false 
    t.date  "end_date",             null: false 
    t.time  "end_time",             null: false 
    ... 
end 

這個表可以有活動,start_date等於end_date,並在不同的日期比start_date結束的其他活動。

我想要做的是建立一個SQL查詢,將返回所有日期兩個日期之間的一些活動。

例如:

  • Activity 1: start_date: 2015-04-15, end_date: 2015-04-15
  • Activity 2: start_date: 2015-04-16, end_date: 2015-04-18

查詢將接收兩個參數:start_dateend_date,例如:

  • start_date: 2015-04-01
  • end_date: 2015-04-30

和執行將返回所有日期與這兩個日期之間的活動。在結果上面的例子將是:

  • 2015年4月15日
  • 2015年4月16日
  • 2015年4月17日
  • 2015年4月18日

該應用程序使用Ruby on Rails編寫,Postgres中包含數據庫。這可以使用Ruby代碼來解決,但我不希望出於性能方面的考慮。

如何使用Postgres中的一條SQL語句實現此查詢?我認爲generate_series Postgres函數可以幫助解決這個問題,但是如何?

回答

4

有了:

INSERT INTO activities VALUES 
    ('2015-04-15', '2015-04-15'), 
    ('2015-04-16', '2015-04-18'), 
    ('2015-04-01', '2015-04-03') 
; 

您可以使用generates_series

SELECT DISTINCT generate_series(start_date, end_date, '1 day'::interval) AS date 
FROM activities 
ORDER BY date; 

┌────────────────────────┐ 
│   date   │ 
├────────────────────────┤ 
│ 2015-04-01 00:00:00+02 │ 
│ 2015-04-02 00:00:00+02 │ 
│ 2015-04-03 00:00:00+02 │ 
│ 2015-04-15 00:00:00+02 │ 
│ 2015-04-16 00:00:00+02 │ 
│ 2015-04-17 00:00:00+02 │ 
│ 2015-04-18 00:00:00+02 │ 
└────────────────────────┘ 
(7 rows) 

編輯:不知怎麼忘了A和B部分之間的

SELECT generate_series('2015-04-10','2015-04-17', '1 day'::interval) AS date -- your input values 
INTERSECT 
    SELECT DISTINCT generate_series(start_date, end_date, '1 day'::interval) AS date 
    FROM activities 
ORDER BY date ASC; 

┌────────────────────────┐ 
│   date   │ 
├────────────────────────┤ 
│ 2015-04-15 00:00:00+02 │ 
│ 2015-04-16 00:00:00+02 │ 
│ 2015-04-17 00:00:00+02 │ 
└────────────────────────┘ 
(3 rows) 
1

如果你要提供的參數:如果你想從數據讓他們

select generate_series(p_startdate, p_enddate, '1 day'::interval) 

,你可以這樣做:

select generate_series(min(startdate), max(enddate), '1 day'::interval 
from activities 

我認爲你正在尋找對於這些組合:

select distinct s.dte 
from activities a join 
    generate_series(p_startdate, p_enddate, '1 day'::interval) s(dte) 
    on s.dte >= a.startdate and s.dte < a.enddate; 
相關問題