如何从指定连续行组而非全量行中提取某列的最早值——以Token分组的日期提取场景为例
解决连续Token=9分组的最早日期问题
这是个典型的SQL「岛屿问题」(连续相同值分组),普通的GROUP BY + MIN(Date)之所以失效,是因为它会把所有Token=9的行都归为一组,完全忽略中间被其他Token打断的连续序列。咱们一步步来搞定这个需求:找到每个用户最新的连续Token=9行组中的最早日期。
先看原始示例场景
原始数据表:
| Name | Token | Date |
|---|---|---|
| John | 7 | 2010-4-30 |
| John | 7 | 2011-4-30 |
| John | 9 | 2011-5-30 |
| John | 9 | 2012-7-30 |
| John | 9 | 2015-1-30 |
| John | 7 | 2016-10-1 |
| John | 9 | 2016-11-3 |
| John | 9 | 2018-1-1 |
| John | 7 | 2021-9-9 |
期望输出:2016-11-3 —— 因为2016-10-1的Token=7打断了之前的连续9序列,最新的连续9组是2016-11-3到2018-1-1,我们要取这组的最早日期。
解决方案:用窗口函数标记连续组
核心思路是先给每个连续的Token=9序列分配唯一的组ID,然后找到每个用户最新的那个组,再取该组的最小日期。这里用窗口函数实现:
WITH token_groups AS ( SELECT Name, Token, Date, -- 生成连续Token=9的组ID:整体行号减去Token=9的累计计数 ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date) - SUM(CASE WHEN Token = 9 THEN 1 ELSE 0 END) OVER (PARTITION BY Name ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS group_id FROM your_table -- 替换成你的实际表名 ), valid_groups AS ( SELECT Name, group_id, MIN(Date) AS earliest_date_in_group, MAX(Date) AS latest_date_in_group FROM token_groups WHERE Token = 9 -- 只保留Token=9的行 GROUP BY Name, group_id ) SELECT Name, earliest_date_in_group AS desired_date FROM valid_groups WHERE (Name, latest_date_in_group) IN ( -- 找到每个用户最新的组(即组内最大日期最大的那个组) SELECT Name, MAX(latest_date_in_group) FROM valid_groups GROUP BY Name );
验证各个案例
案例1
输入表:
| Name | Token | Date |
|---|---|---|
| John | 7 | 2010-4-30 |
| John | 7 | 2011-4-30 |
| John | 9 | 2011-5-30 |
| John | 9 | 2012-7-30 |
运行上述SQL后,输出2011-5-30,符合预期——唯一的连续9组的最早日期就是它。
案例2
输入表:
| Name | Token | Date |
|---|---|---|
| John | 7 | 2010-4-30 |
| John | 7 | 2011-4-30 |
| John | 9 | 2011-5-30 |
| John | 9 | 2012-7-30 |
| John | 9 | 2015-1-30 |
| John | 7 | 2016-10-1 |
| John | 9 | 2016-11-3 |
| John | 9 | 2018-1-1 |
| John | 7 | 2021-9-9 |
| John | 9 | 2022-1-1 |
运行后输出2022-1-1——最新的连续9组只有这一行,直接取它的日期。
案例3
输入表:
| Name | Token | Date |
|---|---|---|
| John | 9 | 2010-4-30 |
| John | 9 | 2011-4-30 |
| John | 9 | 2011-5-30 |
| John | 9 | 2012-7-30 |
| John | 9 | 2015-1-30 |
| John | 9 | 2016-10-1 |
| John | 9 | 2016-11-3 |
| John | 9 | 2018-1-1 |
| John | 7 | 2021-9-9 |
运行后输出2010-4-30——所有Token=9的行属于同一个连续组,这是用户唯一的9组,取它的最早日期。
内容的提问来源于stack exchange,提问作者Rana
相关产品推荐
相关产品推荐

