You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PostgreSQL中查找连续的datetime时间范围序列

PostgreSQL 时间序列连续区间聚合实现

需求背景

每行数据包含以分钟为单位的时长、开始时间与结束时间,时间精度为1分钟或更高,需要将连续的时间序列分组,统计每个连续区间的聚合信息。

表结构与测试数据

CREATE TABLE public."TimeSeries" (
    "Id" uuid NOT NULL,
    "BeginTime" timestamptz NOT NULL,
    "EndTime" timestamptz NOT NULL DEFAULT '0001-01-01 00:00:00' :: timestamp without time zone,
    "LengthMin" int4 NOT NULL
);

INSERT INTO public."TimeSeries" ("Id","BeginTime","LengthMin","EndTime") VALUES
     ('ecabcd8d-3129-4128-b126-a4e1abcd49c9'::uuid,'2021-11-16 11:45:00.000',1,'2021-11-16 11:46:00.000'),
     ('e5abcd70-5125-412b-9128-93ecabcdcba9'::uuid,'2021-11-16 11:46:00.000',1,'2021-11-16 11:47:00.000'),
     ('03abcdb8-8129-4124-b126-f5bbabcd7157'::uuid,'2021-11-16 11:47:00.000',1,'2021-11-16 11:48:00.000'),
     ('54abcdcc-6129-4126-912b-34b2abcde19a'::uuid,'2021-11-16 11:50:00.000',1,'2021-11-16 11:51:00.000'),
     ('77abcd28-212f-4122-912f-5060abcd2aa0'::uuid,'2021-11-16 11:51:00.000',1,'2021-11-16 11:52:00.000'),
     ('8babcdd1-f12a-4124-9128-2529abcda136'::uuid,'2021-11-16 11:52:00.000',1,'2021-11-16 11:53:00.000'),
     ('8aabcd94-9129-4121-b12c-1ebfabcd06b8'::uuid,'2021-11-16 12:35:00.000',1,'2021-11-16 12:36:00.000'),
     ('96abcd04-b12e-4122-b12b-4dc2abcdcee4'::uuid,'2021-11-16 12:40:00.000',1,'2021-11-16 12:41:00.000'),
     ('42abcd4a-f129-412c-9124-41b3abcd3ca3'::uuid,'2021-11-16 12:44:00.000',1,'2021-11-16 12:45:00.000'),
     ('beabcd8f-c12f-4126-a12b-0a37abcdd0bb'::uuid,'2021-11-16 12:49:00.000',1,'2021-11-16 12:50:00.000'),
     ('b8abcd79-d12c-4120-912f-754fabcdd220'::uuid,'2021-11-16 12:50:00.000',1,'2021-11-16 12:51:00.000'),
     ('c3abcd08-e121-4127-b125-4e70abcd5756'::uuid,'2021-11-16 12:59:00.000',1,'2021-11-16 13:00:00.000'),
     ('65abcdbe-7121-412a-a12c-1f68abcd94eb'::uuid,'2021-11-16 13:00:00.000',1,'2021-11-16 13:01:00.000'),
     ('f5abcd38-9122-412c-b12f-957fabcd79b5'::uuid,'2021-11-16 13:05:00.000',1,'2021-11-16 13:06:00.000');

现有查询问题

当前已经可以通过lag窗口函数判断当前行是否与上一行属于同一连续序列,查询代码如下:

SELECT
    "BeginTime" = lag("EndTime") OVER (
        ORDER BY
            "BeginTime"
    ) AS "isInSeries",
    *
FROM
    "TimeSeries"
WHERE
    "LengthMin" = 1
ORDER BY
    "BeginTime"

该查询仅能得到单行列的连续标识,无法将同属一个连续序列的所有行分组聚合。

期望输出

需要统计每个连续序列的起始时间、包含行数、最小开始时间、最大结束时间、总时长,格式如下:

|          SeriesBegin | cnt |                  min |                  max |            delta |
|----------------------|-----|----------------------|----------------------|------------------|
| 2021-11-16T11:45:00Z |   3 | 2021-11-16T11:45:00Z | 2021-11-16T11:48:00Z | 3 mins 0.00 secs |
| 2021-11-16T11:50:00Z |   3 | 2021-11-16T11:50:00Z | 2021-11-16T11:53:00Z | 3 mins 0.00 secs |
| 2021-11-16T12:35:00Z |   1 | 2021-11-16T12:35:00Z | 2021-11-16T12:36:00Z | 1 mins 0.00 secs |
| 2021-11-16T12:40:00Z |   1 | 2021-11-16T12:40:00Z | 2021-11-16T12:41:00Z | 1 mins 0.00 secs |
| 2021-11-16T12:44:00Z |   1 | 2021-11-16T12:44:00Z | 2021-11-16T12:45:00Z | 1 mins 0.00 secs |
| 2021-11-16T12:49:00Z |   2 | 2021-11-16T12:49:00Z | 2021-11-16T12:51:00Z | 2 mins 0.00 secs |
| 2021-11-16T12:59:00Z |   2 | 2021-11-16T12:59:00Z | 2021-11-16T13:01:00Z | 2 mins 0.00 secs |
| 2021-11-16T13:05:00Z |   1 | 2021-11-16T13:05:00Z | 2021-11-16T13:06:00Z | 1 mins 0.00 secs |

实现方案

通过「缺口与岛屿」经典算法实现连续序列分组,先给每个连续序列生成统一的分组ID,再做聚合计算即可,代码如下:

WITH marked_series AS (
    SELECT
        *,
        -- 遇到时间不连续的行时,分组ID+1,同一连续序列的行分组ID相同
        SUM(CASE WHEN "BeginTime" = LAG("EndTime") OVER (ORDER BY "BeginTime") THEN 0 ELSE 1 END) OVER (ORDER BY "BeginTime") AS series_group
    FROM "TimeSeries"
    WHERE "LengthMin" = 1
)
SELECT
    MIN("BeginTime") AS "SeriesBegin",
    COUNT(*) AS "cnt",
    MIN("BeginTime") AS "min",
    MAX("EndTime") AS "max",
    EXTRACT(EPOCH FROM (MAX("EndTime") - MIN("BeginTime")))/60 || ' mins 0.00 secs' AS "delta"
FROM marked_series
GROUP BY series_group
ORDER BY "SeriesBegin";

内容的提问来源于stack exchange,提问作者Fritz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 10:24:07