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

PostgreSQL:如何用LAG()追踪距上次KEEP行时长并标记行状态

SQL标记KEEP/SKIP的解决方案

原始数据

datevalue
2023-08-05 00:00:45.000 -0500174
2023-08-05 00:01:46.000 -0500175
2023-08-05 00:02:46.000 -0500175
2023-08-05 00:03:45.000 -0500174
2023-08-05 00:05:59.000 -0500179
2023-08-05 00:18:45.000 -0500178
2023-08-05 00:21:55.000 -0500178

需求

需要新增output列,值为KEEP或SKIP,逻辑规则:

  • 第一行默认标记为KEEP
  • 后续每行与最近的已标记为KEEP的行比较,若时间间隔超过5分钟则标记为KEEP,否则标记为SKIP

期望输出:

datevalueoutput
2023-08-05 00:00:45.000 -0500174KEEP
2023-08-05 00:01:46.000 -0500175SKIP
2023-08-05 00:02:46.000 -0500175SKIP
2023-08-05 00:03:45.000 -0500174SKIP
2023-08-05 00:05:59.000 -0500179KEEP
2023-08-05 00:18:45.000 -0500178KEEP
2023-08-05 00:21:55.000 -0500178SKIP

现有问题

尝试的SQL仅能和上一行比较,无法关联到最近的KEEP行:

SELECT *, 
     CASE 
        WHEN (date - LAG(date) OVER (ORDER BY date ASC)) > INTERVAL '5 minutes' THEN 'KEEP',
        WHEN LAG(date) OVER (ORDER BY date) IS NULL THEN 'PUSH'
     ELSE 'SKIP'
     END AS output
from table;

比如第5行(00:05:59)和第一行间隔5分14秒,符合KEEP条件,但现有SQL和第四行比较间隔不足5分钟,导致错误标记。

解决方案

这个需求属于递归标记场景,需要用递归CTE来追踪最近的KEEP行时间:

WITH RECURSIVE ranked_data AS (
    -- 先给数据按时间排序,生成行号
    SELECT 
        date, 
        value, 
        ROW_NUMBER() OVER (ORDER BY date) AS rn
    FROM your_table_name
),
keep_track AS (
    -- 初始化:第一行标记为KEEP,记录其时间
    SELECT 
        date, 
        value, 
        rn,
        'KEEP' AS output,
        date AS last_keep_date
    FROM ranked_data
    WHERE rn = 1
    UNION ALL
    -- 递归处理后续行:和最近的KEEP行时间比较
    SELECT 
        rd.date, 
        rd.value, 
        rd.rn,
        CASE 
            WHEN rd.date - kt.last_keep_date > INTERVAL '5 minutes' THEN 'KEEP'
            ELSE 'SKIP'
        END AS output,
        -- 如果当前行是KEEP,更新last_keep_date为当前时间,否则沿用之前的
        CASE 
            WHEN rd.date - kt.last_keep_date > INTERVAL '5 minutes' THEN rd.date
            ELSE kt.last_keep_date
        END AS last_keep_date
    FROM ranked_data rd
    JOIN keep_track kt ON rd.rn = kt.rn + 1
)
SELECT date, value, output
FROM keep_track
ORDER BY date;

逻辑说明

  1. ranked_data:先给原始数据按时间排序并生成行号,方便递归逐行处理。
  2. keep_track递归CTE:
    • 锚点部分:取第一行,标记为KEEP,并记录该行的时间作为last_keep_date。
    • 递归部分:每次处理下一行,和上一步的last_keep_date比较:
      • 若间隔超5分钟,标记为KEEP,并更新last_keep_date为当前行时间。
      • 否则标记为SKIP,沿用之前的last_keep_date。
  3. 最后从递归结果中取出需要的列,按时间排序输出。

适配不同数据库

如果使用MySQL,递归CTE语法一致,但时间间隔计算可能需要调整为TIMESTAMPDIFF(MINUTE, kt.last_keep_date, rd.date) > 5;如果是PostgreSQL,当前语法直接可用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:44:54