如何在SQL中对相似行分组并合并日期区间?
将同一地址的日期合并为区间的SQL实现
原始数据表
| DATE | ADRESS |
|---|---|
| 2010-09-02 | ENGLAND |
| 2010-09-03 | ENGLAND |
| 2010-09-04 | ENGLAND |
| 2010-09-05 | ENGLAND |
| 2010-09-06 | GERMANY |
| 2010-09-07 | GERMANY |
| 2010-09-08 | GERMANY |
| 2011-09-03 | ENGLAND |
| 2012-09-02 | ENGLAND |
| 2013-09-03 | ENGLAND |
期望结果表
| DATE | ADRESS |
|---|---|
| 2010-09-02 - 2010-09-05 | ENGLAND |
| 2010-09-06 - 2010-09-08 | GERMANY |
| 2011-09-03 - 2013-09-03 | ENGLAND |
解决方案
核心是识别同一地址未被其他地址打断的日期分组,再对每组聚合生成日期区间,以下是两种适配不同数据库版本的实现:
方式一:使用窗口函数(支持MySQL 8+、PostgreSQL、SQL Server等)
SELECT CONCAT(MIN(date), ' - ', MAX(date)) AS DATE, adress FROM ( SELECT date, adress, -- 用行号差值标记同一地址的连续分组 ROW_NUMBER() OVER (ORDER BY date) - ROW_NUMBER() OVER (PARTITION BY adress ORDER BY date) AS group_id FROM your_table_name ) t GROUP BY adress, group_id ORDER BY MIN(date);
方式二:使用变量(适配MySQL 5.x等无窗口函数的版本)
SELECT CONCAT(MIN(date), ' - ', MAX(date)) AS DATE, adress FROM ( SELECT date, adress, @group_id := IF(@prev_adress = adress, @group_id, @group_id + 1) AS group_id, @prev_adress := adress FROM your_table_name, (SELECT @prev_adress := '', @group_id := 0) vars ORDER BY date ) t GROUP BY adress, group_id ORDER BY MIN(date);
逻辑说明
- 分组标记:不管用窗口函数还是变量,都是为同一地址且未被其他地址分隔的记录分配相同分组ID,比如2010年的英格兰、2011-2013年的英格兰、德国各为独立分组。
- 聚合生成区间:按地址和分组ID聚合,取每组最小、最大日期,用
CONCAT拼接成区间字符串。 - 排序:按最小日期排序,保证结果顺序符合时间逻辑。
内容的提问来源于stack exchange,提问作者Mark Abde
相关产品推荐
相关产品推荐

