如何 return 使用 Postgres 仅用一条语句在两列之间设置一系列日期?

How to return a series of dates between two columns with just one statement using Postgres?

我有以下 table:

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

此 table 可以有 start_date 等于 end_date 的活动和结束日期不同于 start_date 的其他活动。

我想要做的是构建一个 SQL 查询,该查询将 return 所有日期 与两个之间的一些 activity日期。

例如:

查询会收到两个参数:start_dateend_date,例如:

并且执行将 return 这两个日期之间 activity 的所有日期。在上面的示例中,结果将是:

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

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

有:

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)

如果要提供参数:

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;