0

我有下表:

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-04-15
  • 2015-04-16
  • 2015-04-17
  • 2015-04-18

该应用程序是使用 Ruby on Rails 编写的,数据库位于 Postgres 中。这可以使用 Ruby 代码解决,但出于性能原因,我不想这样做。

如何在 Postgres 中仅使用一条 SQL 语句来实现此查询?我认为generate_seriesPostgres 功能可以帮助解决这个问题,但是如何解决呢?

4

2 回答 2

5

和 :

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)
于 2015-04-04T14:46:01.690 回答
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;
于 2015-04-04T15:08:32.890 回答