SQL中合并重叠与连续日期范围(不使用master..spt_values)
合并重叠/连续日期范围的SQL解决方案
假设你的原始表名为date_ranges,包含字段startdate(起始日期)和enddate(结束日期),如果有分组维度(比如用户IDuser_id),方案也可以适配。
核心思路
利用窗口函数标记出所有重叠或连续的日期区间为同一组,再按组聚合得到合并后的日期范围:
- 用
LAG()获取上一条记录的结束日期,判断当前区间是否与上一个区间重叠/连续 - 通过累加标记生成分组ID
- 按分组ID聚合,取每组的最小起始日期和最大结束日期
无分组维度的SQL实现
WITH grouped_ranges AS ( SELECT startdate, enddate, -- 标记当前区间是否与上一个区间断开:如果当前startdate > 上一个enddate+1,则视为新组 SUM(CASE WHEN startdate > DATEADD(day, 1, LAG(enddate) OVER (ORDER BY startdate)) THEN 1 ELSE 0 END) OVER (ORDER BY startdate) AS group_id FROM date_ranges ) SELECT MIN(startdate) AS merged_startdate, MAX(enddate) AS merged_enddate FROM grouped_ranges GROUP BY group_id ORDER BY merged_startdate;
带分组维度的SQL实现(如按用户ID分组)
如果你的数据是按某维度分组(比如每个用户的日期范围),只需在窗口函数中加入PARTITION BY:
WITH grouped_ranges AS ( SELECT user_id, startdate, enddate, SUM(CASE WHEN startdate > DATEADD(day, 1, LAG(enddate) OVER (PARTITION BY user_id ORDER BY startdate)) THEN 1 ELSE 0 END) OVER (PARTITION BY user_id ORDER BY startdate) AS group_id FROM date_ranges ) SELECT user_id, MIN(startdate) AS merged_startdate, MAX(enddate) AS merged_enddate FROM grouped_ranges GROUP BY user_id, group_id ORDER BY user_id, merged_startdate;
说明
DATEADD(day, 1, LAG(enddate))是为了处理连续日期(比如上一个区间结束于2023-01-05,当前区间开始于2023-01-06,视为连续需要合并)- 如果只需要合并重叠日期,不需要合并连续的,把判断条件改成
startdate > LAG(enddate) OVER (...)即可
内容的提问来源于stack exchange,提问作者PRI
相关产品推荐
相关产品推荐

