SQL Server合并相邻同名重复行 取最小更新日期升序查询
相邻同名字段合并取最小更新日期SQL实现
需求说明
- 合并规则:仅对相邻行Name字段值相同的行做合并,非相邻的同名行不做合并
- 聚合规则:每个合并分组取
UpdatedDate字段的最小值 - 排序规则:最终返回结果按
UpdatedDate字段升序排列
测试数据
原始表数据
Name UpdatedDate L 05-May-2022 S 09-May-2022 S 09-May-2022 A 10-May-2022 A 15-May-2022 L 16-May-2022 S 17-May-2022 S 19-May-2022 K 01-May-2022
预期输出结果
Name UpdatedDate K 01-May-2022 L 05-May-2022 S 09-May-2022 A 10-May-2022 L 16-May-2022 S 17-May-2022
实现思路
该需求属于经典的**间隙与岛屿(Gaps and Islands)**问题,核心是给连续相邻的同名行生成统一的分组标识,再做聚合:
- 按数据原始存储顺序生成全局行号,保证相邻关系不被打乱
- 按Name分区,给每个同名值单独生成分区内的行号
- 全局行号与分区内行号做差值,连续相邻的同名行计算出的差值完全相同,以此作为分组ID
- 按Name+分组ID聚合,取每组
UpdatedDate最小值,最后按聚合结果升序排序即可
可运行代码(支持MySQL8+/PostgreSQL/SQL Server/Oracle等主流支持窗口函数的数据库)
WITH raw_with_rn AS ( SELECT Name, UpdatedDate, -- 若表有自增ID/插入时间等可明确原始顺序的字段,可替换ORDER BY子句内容保证顺序准确 ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS global_rn FROM your_table -- 替换为实际表名 ), group_with_tag AS ( SELECT Name, UpdatedDate, global_rn, -- 计算分组标识:连续同名行的差值一致 global_rn - ROW_NUMBER() OVER (PARTITION BY Name ORDER BY global_rn) AS group_tag FROM raw_with_rn ) SELECT Name, MIN(UpdatedDate) AS UpdatedDate FROM group_with_tag GROUP BY Name, group_tag ORDER BY MIN(UpdatedDate) ASC;
注意事项
- 禁止直接使用
GROUP BY Name聚合:该写法会将所有同名行(无论是否相邻)全部合并,会把案例中两次出现的L、两次出现的S错误合并为单条,不符合需求 - 全局行号的生成必须严格匹配数据的原始相邻顺序:如果表存在自增主键、写入时间戳等可明确标识行存储顺序的字段,建议替换第一个CTE中的排序逻辑,避免数据库底层存储变动导致相邻判断错误
- 如果使用不支持窗口函数的老版本数据库(如MySQL5.x),需要用用户变量手动实现行号计算逻辑,核心分组思路一致
内容的提问来源于stack exchange,提问作者sarath
相关产品推荐
相关产品推荐

