如何 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日期。
例如:
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_date
和end_date
,例如:
start_date: 2015-04-01
end_date: 2015-04-30
并且执行将 return 这两个日期之间 activity 的所有日期。在上面的示例中,结果将是:
- 2015-04-15
- 2015-04-16
- 2015-04-17
- 2015-04-18
该应用程序是在 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;
我有以下 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日期。
例如:
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_date
和end_date
,例如:
start_date: 2015-04-01
end_date: 2015-04-30
并且执行将 return 这两个日期之间 activity 的所有日期。在上面的示例中,结果将是:
- 2015-04-15
- 2015-04-16
- 2015-04-17
- 2015-04-18
该应用程序是在 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;