使用 postgres generate_series 生成定期计划

Posted

技术标签:

【中文标题】使用 postgres generate_series 生成定期计划【英文标题】:Using postgres generate_series to generate a recurring schedule 【发布时间】:2018-09-20 04:16:18 【问题描述】:

我有一个名为Events 的重复日期表,我如何获取此表并根据事件 wday 和时间从系列中生成具体即将到来的日期? (例如只有 wday "mondays" 和开始时间 "7pm" 是重要的)

事件

+-----+---------------------------+---------------------+
| id  | start_at                  | recurring_schedule  |
+-----+---------------------------+---------------------+
| 358 | 2015-01-23 20:00:00 +0000 | Weekly              |
| 359 | 2016-01-22 19:30:00 +1100 | Monthly             |
| 360 | 2016-02-01 19:00:00 +1100 | Weekly              |
| 361 | 2016-02-01 20:00:00 +0000 | Weekly              |
| 362 | 2014-02-13 20:00:00 +0000 | Bi-Weekly           |
+-----+---------------------------+---------------------+
start_at(日期时间,用于DOW和开始时间,忽略实际日期)

为简单起见,您可以忽略重复安排并假设所有事件都是每周一次,例如总是在一周的同一天。

我怎样才能把这样的表格转换成这样的:

未来日志

+----------+---------------------------+
| event_id | start_at                  |
+----------+---------------------------+
| 35       | 2018-04-11 19:30:00 +0000 |
| 94       | 2018-04-12 20:00:00 +0100 |
| 269      | 2018-04-13 18:30:00 +0100 |
| 45       | 2018-04-13 20:00:00 +0100 |
| 242      | 2018-04-13 19:30:00 +1100 |    
| 35       | 2018-04-18 19:30:00 +0000 |
| 94       | 2018-04-19 20:00:00 +0100 |
| 269      | 2018-04-20 18:30:00 +0100 |
| 45       | 2018-04-20 20:00:00 +0100 |
| 242      | 2018-04-20 19:30:00 +1100 |
+----------+---------------------------+

例如,我想SELECT FROM events 理论事件,并使用诸如 generate_series 之类的东西从每个事件中创建 6-8 周的未来日期来构建事件时间线。

【问题讨论】:

我相信是简单的 json,但你可以忽略它,对于这个例子,你可以假设它们每周在同一天的同一时间重复出现,例如每周一晚上 7:30。跨度> 【参考方案1】:

更新答案:

在案例语句中使用 generate_series 来构建序列,类似于我在原始答案中所做的那样,根据recurring_schedule 列使用不同的频率。

将您希望系列生成的日期指定为绝对日期'2020-01-01'::timestamptz,如下所示,您可以传递相对日期,例如NOW() + INTERVAL '10 weeks' 代替。

SELECT id event_id, start_at, 
CASE recurring_schedule 
    WHEN 'Weekly' 
        THEN GENERATE_SERIES(start_at, '2020-01-01'::timestamptz, '1 weeks'::INTERVAL)
    WHEN 'Bi-Weekly'
        THEN GENERATE_SERIES(start_at, '2020-01-01'::timestamptz, '2 weeks'::INTERVAL)
    WHEN 'Monthly'
        THEN GENERATE_SERIES(start_at, '2020-01-01'::timestamptz, '1 month'::INTERVAL)
    ELSE NULL 
END recurring_start_time
FROM events;

带有 json 字段的架构的原始答案:

datetime 类型的 generate_series 的语法是

generate_series(start_time, end_time, step_interval)

由于您的日程安排在 JSON 中包含时间间隔,因此您可以这样构造查询,并根据需要添加更多日程安排类型。

WITH test (id, start_at, place_id, recurring_schedule) AS (

VALUES 
(358, '2015-01-23 20:00:00 +0000'::TIMESTAMPTZ, 412, 
'"validations":"day":[2],"rule_type":"IceCube::WeeklyRule","interval":1,"week_start":0'::JSONB),

(359, '2016-01-22 19:30:00 +1100', 414,
'"validations":"day":[1],"rule_type":"IceCube::WeeklyRule","interval":1,"week_start":0'),

(360, '2016-02-01 19:00:00 +1100', 415, 
'"validations":"day":[4],"rule_type":"IceCube::WeeklyRule","interval":1,"week_start":0'),

(361, '2016-02-01 20:00:00 +0000', 416, 
'"validations":"day":[4],"rule_type":"IceCube::WeeklyRule","interval":1,"week_start":0'),

(362, '2014-02-13 20:00:00 +0000', 417,
'"validations":"day":[2],"rule_type":"IceCube::WeeklyRule","interval":1,"week_start":0')
)
SELECT id, start_at, place_id, 
CASE recurring_schedule->>'rule_type' 
    WHEN 'IceCube::WeeklyRule' 
        THEN GENERATE_SERIES(start_at, NOW(), (recurring_schedule->>'interval' || ' WEEK')::INTERVAL)
    ELSE NULL 
END recurring_start_time
FROM test;

【讨论】:

谢谢,但我如何将其用作嵌套查询,例如 SELECT from events 而不是 WITH 我不确定我是否遵循您的困惑。 with 子句只是将样本数据放在名为test 的视图中。实际查询以SELECT id, start_at, place_id, ... 开头。将From test 替换为FROM events 我已更新问题以使其不那么复杂。抱歉,我之前不是更清楚。 最后一个问题,我怎样才能将系列中的 start_at 日期转换为相同的 WDAY,但从本周(或即将到来的一周)开始?例如 2013-01-01 -> 2018-04-24(星期二) 例如我只关心 start_at 列中的 WDAY,而不是实际日期,我只关心它在当前未来日期的相对值。

以上是关于使用 postgres generate_series 生成定期计划的主要内容,如果未能解决你的问题,请参考以下文章

夏令时更改的 generate_series - 不同的结果取决于服务器时区

Postgres 生成系列

从表中的开始日期和结束日期在 Postgres 中生成系列

如何使用 generate_series() 生成值网格

如何使用 Redshift 交叉连接 generate_series 和 table?

不能在 Redshift 上使用 JOIN 和 generate_series