ale*_*dam 6 postgresql group-by gaps-and-islands datetime postgresql-9.5
我很想知道如何创建一个视图,以 10 分钟最接近 10 分钟的间隔分组时间戳,并包含每个最小和最大时间戳。
所以一个看起来像这样的表:
| Hero | timestamp |
| Batman | 2016-12-08 12:00:00 |
| Batman | 2016-12-08 12:07:00 |
| Batman | 2016-12-08 13:00:00 |
| Batman | 2016-12-08 14:00:00 |
| Wonder Woman | 2016-12-08 10:15:00 |
| Wonder Woman | 2016-12-08 10:18:00 |
| Wonder Woman | 2016-12-08 10:25:00 |
| Wonder Woman | 2016-12-08 10:30:00 |
Run Code Online (Sandbox Code Playgroud)
会导致这样的观点
| Hero | start_time | end_time |
| Batman | 2016-12-08 12:00:00 | 2016-12-08 12:07:00 |
| Wonder Woman | 2016-12-08 10:15:00 | 2016-12-08 10:30:00 |
Run Code Online (Sandbox Code Playgroud)
或这个:
| Hero | start_time | end_time |
| Batman | 2016-12-08 13:00:00 | NULL |
| Batman | 2016-12-08 14:00:00 | NULL |
| Batman | 2016-12-08 12:00:00 | 2016-12-08 12:07:00 |
| Wonder Woman | 2016-12-08 10:15:00 | 2016-12-08 10:30:00|
Run Code Online (Sandbox Code Playgroud)
任何一种解决方案都可以。
我建议按“小时”和 10 分钟间隔的组合进行分组:
SELECT hero
, min(timestamp) AS start_time
, CASE WHEN count(*) > 1 THEN max(timestamp) END AS end_time
FROM tbl
GROUP BY hero
, date_trunc('hour', timestamp)
, EXTRACT(MINUTE FROM timestamp)::int / 10
ORDER BY 1, 2; -- optional
Run Code Online (Sandbox Code Playgroud)
请参阅手册中的日期/时间函数和运算符一章。
EXTRACT(minute FROM timestamp)
提取时间的分钟部分 表达式。转换为整数 ( ::int
) 后,整数除法 ( / 10
) 有效地舍入到 10 分钟间隔 ( 0
- 5
)。
的CASE
表达只增加了一个end_time
,如果多于一个的行落在相同的10分钟间隔。
我建议不要使用“时间戳”作为标识符。它是标准 SQL 中的保留字,也是 Postgres 中的基本数据类型。
如果“组”是由同一英雄的行之间的 10 分钟或更长时间的间隔定义的:
SELECT hero
, count(*) AS ct -- optional
, min(timestamp) AS start_time
, CASE WHEN count(*) > 1 THEN max(timestamp) END AS end_time
FROM (
SELECT hero, timestamp, count(step OR NULL) OVER (ORDER BY hero, timestamp) AS grp
FROM (
SELECT *
, lag(timestamp) OVER (PARTITION BY hero ORDER BY timestamp)
< timestamp - interval '10 min' AS step
FROM tbl
) sub1
) sub2
GROUP BY hero, grp;
Run Code Online (Sandbox Code Playgroud)
详细解释:
db<>fiddle here
旧的 sqlfiddle