“连续时间段内的断点缺失数据”指时间区间本应首尾相接(如09:00–10:00、10:00–11:00),但因中间某段(如11:00–12:00)完全缺失,导致前条end_time与后条start_time之间出现空隙;需用LAG()按start_time排序后比对,筛选start_time > LAG(end_time)且LAG(end_time)非NULL的记录,精准定位断点起止。

什么是“连续时间段内的断点缺失数据”
你有一张记录时间区间的表(比如 events),字段含 start_time 和 end_time,时间本应首尾相接(如 09:00–10:00,10:00–11:00),但中间漏了一段(如 11:00–12:00 缺失),导致出现“断点”。你要快速找出这些断点——即前一条的 end_time 和后一条的 start_time 之间存在空隙的位置。
关键不是查“有没有重叠”,而是查“有没有缝隙”。直接用 GROUP BY 或窗口函数排序后错位比对最稳,JOIN 是辅助手段,不是主逻辑。
用 LAG() + 自连接识别时间缝隙(PostgreSQL / SQL Server / MySQL 8.0+)
别写两层子查询再 JOIN,先用窗口函数把“上一行的 end_time”拉到当前行,再做一次简单比较。这是最轻量、可读性最强的做法。
-
LAG(end_time) OVER (ORDER BY start_time)必须按start_time排序,否则顺序错乱,缝隙判断全失效 - 如果存在多条相同
start_time的记录,需加次级排序(如ORDER BY start_time, id),否则LAG()行为不确定 - 空隙判定条件是:
start_time > LAG(end_time),注意不是>=——等于表示紧邻,不构成缺失 - 第一行的
LAG(end_time)是NULL,要显式过滤掉,否则会误报一个“从开头到第一条 start_time”的假缝隙
SELECT
prev_end AS gap_start,
start_time AS gap_end
FROM (
SELECT
start_time,
LAG(end_time) OVER (ORDER BY start_time) AS prev_end
FROM events
) t
WHERE start_time > prev_end AND prev_end IS NOT NULL;
MySQL 5.7 或旧版 SQLite 怎么办?用自连接模拟 LAG()
没有窗口函数时,得靠 JOIN 手动找“上一条”。核心思路:对每条记录 e1,找所有 e2.start_time 的记录,再取其中 <code>start_time 最大的那条作为前驱。
- 必须加
ON e2.start_time ,不能只写 <code>WHERE,否则变成笛卡尔积再过滤,性能爆炸 -
LEFT JOIN是必须的——第一行没前驱,也要保留,后续靠e2.end_time IS NOT NULL过滤掉 - 子查询或 CTE 中提前
SELECT DISTINCT start_time, end_time,避免重复时间点干扰MAX()判定 - 这个写法在万级数据上可能变慢,建议给
start_time加索引
SELECT
e2.end_time AS gap_start,
e1.start_time AS gap_end
FROM events e1
LEFT JOIN events e2
ON e2.start_time = (
SELECT MAX(e2_inner.start_time)
FROM events e2_inner
WHERE e2_inner.start_time < e1.start_time
)
WHERE e1.start_time > e2.end_time AND e2.end_time IS NOT NULL;
为什么不要用 FULL OUTER JOIN 或 UNION ALL 拼边界?
有人想把所有 start_time 和 end_time 提出来,UNION ALL 成一列,再排序找相邻差值。这方法看似直观,但实际踩坑极多:
- 同一时刻既是某段终点又是下一段起点(如 10:00),
UNION ALL后会重复,排序后无法区分角色,缝隙被掩盖 - 缺少原始行关联信息,查出缝隙后不知道它夹在哪两条记录之间,定位修复困难
- 若存在
NULL时间值,UNION ALL会静默丢弃或引发类型隐式转换错误 - SQL Server 中
FULL OUTER JOIN在无匹配时补NULL,但时间字段本身可能是NULL,真假难辨
断点的本质是“有序序列中相邻元素的关系”,强行打散再拼接,等于放弃顺序上下文——越绕越容易出错。

















