Oracle SQL实现按Event_Name合并重叠区间的查询方案
合并同类别下的重叠/连续时间区间
需求说明
基于Event_Name字段,合并同一类别下重叠或连续的时间区间,最终得到区间唯一、记录更精简的数据集。
数据示例
原始数据
| ID | Event_Name | Start_Date | End_Date |
|---|---|---|---|
| 1 | Event A | 2023-01-01 | 2023-01-05 |
| 2 | Event A | 2023-01-03 | 2023-01-10 |
| 3 | Event A | 2023-01-12 | 2023-01-15 |
| 4 | Event B | 2023-02-01 | 2023-02-03 |
| 5 | Event B | 2023-02-04 | 2023-02-08 |
| 6 | Event C | 2023-03-01 | 2023-03-02 |
目标结果
| Event_Name | Merged_Start | Merged_End |
|---|---|---|
| Event A | 2023-01-01 | 2023-01-10 |
| Event A | 2023-01-12 | 2023-01-15 |
| Event B | 2023-02-01 | 2023-02-08 |
| Event C | 2023-03-01 | 2023-03-02 |
SQL解决方案
使用窗口函数标记区间组,再按组聚合合并区间,适用于大部分支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server等):
WITH ranked_events AS ( SELECT Event_Name, Start_Date, End_Date, -- 标记新的区间组:当前区间与前一个不重叠/不连续时,开启新组 SUM( CASE WHEN LAG(End_Date) OVER (PARTITION BY Event_Name ORDER BY Start_Date) >= Start_Date THEN 0 ELSE 1 END ) OVER (PARTITION BY Event_Name ORDER BY Start_Date) AS group_id FROM your_table_name -- 替换为你的表名 ) SELECT Event_Name, MIN(Start_Date) AS Merged_Start, MAX(End_Date) AS Merged_End FROM ranked_events GROUP BY Event_Name, group_id ORDER BY Event_Name, Merged_Start;
逻辑解释
- 标记区间组:通过
LAG()函数获取同类别下前一条记录的结束日期,判断当前区间是否与前一个重叠(当前开始日期 ≤ 前一个结束日期),如果不重叠则标记为新组,通过累加生成唯一的group_id。 - 合并区间:按
Event_Name和group_id分组,取每组的最早开始日期和最晚结束日期,得到合并后的完整区间。
调整说明
如果需要将连续日期(比如前一个结束日期是2023-01-10,当前开始日期是2023-01-11)视为可合并的区间,可修改CASE条件:
CASE WHEN LAG(End_Date) OVER (PARTITION BY Event_Name ORDER BY Start_Date) + INTERVAL 1 DAY >= Start_Date THEN 0 ELSE 1 END
不同数据库的日期加减语法略有差异,比如SQL Server用DATEADD(day, 1, LAG(End_Date) ...),PostgreSQL用LAG(End_Date) ... + INTERVAL '1 day'。
内容的提问来源于stack exchange,提问作者szakwani
相关产品推荐
相关产品推荐

