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

PostgreSQL中如何筛选超时非计划事件的最近计划事件

解决超时非计划事件匹配最近计划事件的SQL问题

表结构与示例数据

DeliveryEvent表按delivery_id分组,事件类型定义:

  • event_type=2:scheduled(计划事件)
  • event_type=3:unscheduled(非计划事件)
  • event_type=4:completed(完成事件)
idcreatedevent_typedelivery_idextra
12022-10-27 18:04210005
22022-10-27 19:00310005{"couldn't deliver"}
32022-10-27 19:20210005
42022-10-27 20:30310005{"timeout"}
52022-10-27 21:15210005
62022-10-27 22:40310005{"timeout"}
72022-10-27 22:55210005
82022-10-27 23:00410005

需求

针对每个因timeout产生的非计划事件(event_type=3且extra包含timeout),获取其紧接的前一个计划事件,用于计算两者的时间间隔。

原查询问题

当前执行的SQL会返回每个超时非计划事件与所有之前计划事件的组合,不符合需求(已修正原SQL的表别名与extra判断错误):

SELECT    
    scheduled.id as scheduled_id, 
    scheduled.created as scheduled_time, 
    scheduled.event_type as scheduled_event, 
    scheduled.delivery_id as delivery_id,
    unscheduled.id as unscheduled_id, 
    unscheduled.created as unscheduled_time, 
    unscheduled.event_type as unscheduled_event, 
    unscheduled.extra as extra
FROM    
    delivery_event scheduled
JOIN    
    delivery_event unscheduled ON scheduled.delivery_id = 10005 
    AND unscheduled.delivery_id = 10005 
    AND unscheduled.event_type = 3 
    AND scheduled.event_type = 2 
    AND scheduled.created < unscheduled.created
    AND unscheduled.extra->>'timeout' IS NOT NULL

该查询会出现一个超时事件匹配多个历史计划事件的情况,我们需要的是每个超时事件对应的最近的前一个计划事件。

解决方案

方法1:使用LATERAL JOIN(PostgreSQL适用)

针对每个超时事件,直接关联查询出最近的前一个计划事件:

SELECT
    s.id as scheduled_id,
    s.created as scheduled_time,
    s.event_type as scheduled_event,
    s.delivery_id,
    u.id as unscheduled_id,
    u.created as unscheduled_time,
    u.event_type as unscheduled_event,
    u.extra
FROM
    delivery_event u
LEFT JOIN LATERAL (
    SELECT *
    FROM delivery_event s
    WHERE s.delivery_id = u.delivery_id
      AND s.event_type = 2
      AND s.created < u.created
    ORDER BY s.created DESC
    LIMIT 1
) s ON TRUE
WHERE
    u.event_type = 3
    AND u.extra->>'timeout' IS NOT NULL
    AND u.delivery_id = 10005;

方法2:使用窗口函数(通用SQL)

先为每个事件标记出之前最近的计划事件时间,再关联匹配对应的计划事件:

WITH all_events AS (
    SELECT
        *,
        -- 为每个事件找到之前最近的计划事件时间
        MAX(CASE WHEN event_type = 2 THEN created END) OVER (
            PARTITION BY delivery_id
            ORDER BY created
            ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
        ) AS last_scheduled_time
    FROM delivery_event
    WHERE delivery_id = 10005
)
SELECT
    s.id as scheduled_id,
    s.created as scheduled_time,
    s.event_type as scheduled_event,
    s.delivery_id,
    u.id as unscheduled_id,
    u.created as unscheduled_time,
    u.event_type as unscheduled_event,
    u.extra
FROM all_events u
JOIN delivery_event s 
    ON s.delivery_id = u.delivery_id
    AND s.created = u.last_scheduled_time
    AND s.event_type = 2
WHERE
    u.event_type = 3
    AND u.extra->>'timeout' IS NOT NULL;

预期结果

执行上述任一查询后,将得到每个超时非计划事件对应的最近计划事件:

scheduled_idscheduled_timescheduled_eventdelivery_idunscheduled_idunscheduled_timeunscheduled_eventextra
52022-10-27 21:1521000562022-10-27 22:403{"timeout"}
32022-10-27 19:2021000542022-10-27 20:303{"timeout"}

内容的提问来源于stack exchange,提问作者Laís Alencar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:05:17