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

按ID识别日期重叠并合并日期区间的技术需求

刚好之前处理过一模一样的日期区间合并需求,给你分享两种实用的解决方案,分别适配数据库和Python数据处理场景,直接就能用:

解决方案1:SQL实现(适用于数据库中的数据集)

核心思路是按ID分组,对每个ID下的日期区间按起始日期排序,通过窗口函数追踪当前累积的最大结束日期,判断当前区间是否和前面的合并区间重叠。

下面是通用SQL写法(适配大多数支持窗口函数的数据库,比如PostgreSQL、MySQL 8.0+、SQL Server等):

WITH ranked_intervals AS (
    SELECT 
        ID,
        Start,
        End,
        -- 生成合并组标识:当前区间起始 <= 前面所有区间的最大结束则归为同一组,否则新建组
        SUM(CASE WHEN Start <= LAG(MaxEnd, 1, Start) OVER (PARTITION BY ID ORDER BY Start) THEN 0 ELSE 1 END) 
            OVER (PARTITION BY ID ORDER BY Start) AS group_id
    FROM (
        SELECT 
            ID,
            Start,
            End,
            -- 追踪从第一个区间到当前行的最大结束日期
            MAX(End) OVER (PARTITION BY ID ORDER BY Start ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS MaxEnd
        FROM your_table -- 替换成你的表名
    ) t
)
SELECT 
    ID,
    MIN(Start) AS Merged_Start,
    MAX(End) AS Merged_End
FROM ranked_intervals
GROUP BY ID, group_id
ORDER BY ID, Merged_Start;

逻辑说明:

  1. 内层子查询用MAX(End) OVER (...)计算到当前行为止的最大结束日期,这样能知道前面所有区间的最晚结束时间
  2. 外层用SUM(CASE...) OVER (...)生成分组ID:如果当前区间的Start <= 前面的最大End,说明和前面的区间重叠或连续,属于同一组;否则是新的独立组
  3. 最后按ID和group_id分组,取每组的最小Start和最大End,就是合并后的连续区间
解决方案2:Python Pandas实现(适用于本地数据集)

如果你的数据是在本地用Pandas处理,这个方法更灵活:

import pandas as pd

# 示例数据(替换成你的数据集)
data = {
    'ID': [1,1,1,6,5,4],
    'Start': ['2007-02-01', '2007-03-01', '2007-09-01', '2011-02-05', '2012-11-16', '2015-01-03'],
    'End': ['2007-03-03', '2007-03-31', '2008-07-31', '2011-03-12', '2012-12-26', '2015-01-10']
}
df = pd.DataFrame(data)

# 先把日期列转换成datetime类型,方便比较
df['Start'] = pd.to_datetime(df['Start'])
df['End'] = pd.to_datetime(df['End'])

def merge_intervals(group):
    # 对当前ID的所有区间按起始日期排序
    sorted_group = group.sort_values('Start')
    merged = []
    for _, row in sorted_group.iterrows():
        if not merged:
            # 第一个区间直接加入合并列表
            merged.append([row['Start'], row['End']])
        else:
            last_start, last_end = merged[-1]
            # 如果当前区间的起始 <= 上一个合并区间的结束,说明重叠/连续,更新结束日期
            if row['Start'] <= last_end:
                merged[-1][1] = max(last_end, row['End'])
            else:
                # 不重叠,新增一个合并区间
                merged.append([row['Start'], row['End']])
    # 把合并后的结果转换成DataFrame,带上当前ID
    return pd.DataFrame(merged, columns=['Merged_Start', 'Merged_End']).assign(ID=group['ID'].iloc[0])

# 按ID分组应用合并函数,然后拼接所有结果
merged_df = df.groupby('ID').apply(merge_intervals).reset_index(drop=True)
print(merged_df)

逻辑说明:

  1. 先转换日期格式,确保能正确比较大小
  2. 定义合并函数:对每个ID的组先排序,然后逐个遍历区间,和最后一个合并区间对比,重叠则合并,否则新增
  3. 用groupby.apply把函数应用到每个ID组,最后拼接得到最终的合并结果

用你的示例数据测试的话,ID1会得到两个合并区间:2007-02-01到2007-03-31,以及2007-09-01到2008-07-31,其他ID保持原区间,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:33:00