Postgres 将时间范围分割为 1 分钟时段,没有舍入边界

问题描述 投票:0回答:2

我有一个带有时间戳列的 postgres 表:

开始日期时间 结束日期时间 持续时间 id
2021-10-17 03:13:00 2021-10-17 03:15:02 302 6214550
2021-10-17 03:15:02 2021-10-17 03:17:03 4,021 6214551

我需要将其分成限制在分钟结束或

end_datetime
的桶中,如下:

开始日期时间 结束日期时间 id
2021-10-17 03:13:00 2021-10-17 03:14:00 6214550
2021-10-17 03:14:00 2021-10-17 03:15:00 6214550
2021-10-17 03:15:00 2021-10-17 03:15:02 6214550
2021-10-17 03:15:02 2021-10-17 03:16:00 6214551
2021-10-17 03:16:00 2021-10-17 03:17:00 6214551
2021-10-17 03:17:00 2021-10-17 03:17:03 6214551
sql postgresql date-range generate-series
2个回答
1
投票

架构(PostgreSQL v15)

CREATE TABLE t (
    "start_datetime" TIMESTAMP,
    "end_datetime" TIMESTAMP,
    "duration" INT,
    "id" INTEGER
);

INSERT INTO t
("start_datetime", "end_datetime", "duration", "id")
VALUES
('2021-10-17 03:13:00', '2021-10-17 03:15:02', '302', '6214550'),
('2021-10-17 03:15:02', '2021-10-17 04:17:03', '4021', '6214551');

查询#1

SELECT id
     -- Since we truncated down to the minute in the generate_series, we need to handle the first datetime differently,
     -- choosing it over any datetime before it
     , CASE WHEN start_datetime > m THEN start_datetime ELSE m END AS start_datetime
     -- We find the next minute (ie end_datetime) using LEAD(), except for the last row (per id) as it doesn't exist.
     -- When that's the case, we use end_datetime
     , COALESCE(LEAD(m) OVER(PARTITION BY id ORDER BY m), t.end_datetime) AS end_datetime
FROM t, generate_series(date_trunc('minute', start_datetime), end_datetime, '1 minute'::interval) AS f(m)
ORDER BY id, m;
id 开始日期时间 结束日期时间
6214550 2021-10-17T03:13:00.000Z 2021-10-17T03:14:00.000Z
6214550 2021-10-17T03:14:00.000Z 2021-10-17T03:15:00.000Z
6214550 2021-10-17T03:15:00.000Z 2021-10-17T03:15:02.000Z
6214551 2021-10-17T03:15:02.000Z 2021-10-17T03:16:00.000Z
6214551 2021-10-17T03:16:00.000Z 2021-10-17T03:17:00.000Z
... 被截断
6214551 2021-10-17T04:16:00.000Z 2021-10-17T04:17:00.000Z
6214551 2021-10-17T04:17:00.000Z 2021-10-17T04:17:03.000Z

在 DB Fiddle 上查看


0
投票

Cross join
每行到
generate_series()
生成 1 分钟时段,使用
greatest()
least()
保持不对齐的开始和结束时间戳。
db<>fiddle 的演示

select greatest(slot,start_datetime)   as start_datetime
     , least(slot+'1min',end_datetime) as end_datetime
     , id
from test
cross join lateral generate_series( date_trunc('minute',start_datetime)
                                   ,end_datetime
                                   ,'1min') as slot;
开始日期时间 结束日期时间 id
2021-10-17 03:13:00 2021-10-17 03:14:00 6214550
2021-10-17 03:14:00 2021-10-17 03:15:00 6214550
2021-10-17 03:15:00 2021-10-17 03:15:02 6214550
2021-10-17 03:15:02 2021-10-17 03:16:00 6214551
2021-10-17 03:16:00 2021-10-17 03:17:00 6214551
2021-10-17 03:17:00 2021-10-17 03:17:03 6214551
© www.soinside.com 2019 - 2024. All rights reserved.