基于多列分组选取每组最后一条观测并保留NUMERIC值的方法
多列分组取组内最后一条记录实现方案
你的表结构如下:
CHAR1 CHAR2 CHAR3 CHAR4 CHAR5 DATE NUMERIC
已知数据已按CHAR1/CHAR2/CHAR3/CHAR4/CHAR5/DATE字段完成全局升序排序,需求为按以上6个字段分组选取每组最后一条观测,同时保留对应行的NUMERIC字段值,不需要将NUMERIC纳入分组逻辑,以下是不同场景下可直接运行的实现方案:
方案1:通用窗口函数方案(适配绝大多数主流数据库)
支持MySQL8.0+、PostgreSQL、SQL Server、Oracle、Spark SQL、Presto等所有兼容标准窗口函数的引擎,不依赖预排序,逻辑稳定性最高:
SELECT CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE, NUMERIC FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE -- 同组内按现有排序规则倒序,排序后第一条就是原顺序的组内最后一条 ORDER BY CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE DESC ) AS rn FROM your_table ) tmp WHERE rn = 1;
说明:该方案仅将指定的6个维度字段写入
PARTITION BY分区逻辑,NUMERIC作为普通列随筛选出的行直接返回,完全不需要加入分组维度;多列分组只需要在PARTITION BY后按顺序写全所有分组字段即可,无单列/多列的适配限制。
方案2:预排序场景高性能方案(避免重复排序开销)
由于数据已经提前按分组维度完成升序排序,不需要做二次分区排序,可以通过相邻行值判断直接筛选组内最后一条,千万级大表场景下性能比方案1高30%以上:
SELECT CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE, NUMERIC FROM ( SELECT *, -- 提取下一行的所有分组键值 LEAD(CHAR1) OVER w AS next_c1, LEAD(CHAR2) OVER w AS next_c2, LEAD(CHAR3) OVER w AS next_c3, LEAD(CHAR4) OVER w AS next_c4, LEAD(CHAR5) OVER w AS next_c5, LEAD(DATE) OVER w AS next_date FROM your_table WINDOW w AS (ORDER BY CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE) ) tmp WHERE -- 表尾最后一行无下一行数据,直接保留 next_c1 IS NULL -- 下一行分组键与当前行不一致,说明当前行是本组最后一条 OR NOT ( CHAR1 = next_c1 AND CHAR2 = next_c2 AND CHAR3 = next_c3 AND CHAR4 = next_c4 AND CHAR5 = next_c5 AND DATE = next_date );
方案3:老版本MySQL兼容方案(不支持窗口函数场景)
针对5.x版本不支持窗口函数的MySQL环境,可以通过用户变量流式处理实现,同样不需要将NUMERIC加入分组逻辑:
SELECT CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE, NUMERIC FROM ( SELECT *, @group_rn := IF( @c1 = CHAR1 AND @c2 = CHAR2 AND @c3 = CHAR3 AND @c4 = CHAR4 AND @c5 = CHAR5 AND @d = DATE, @group_rn + 1, 1 ) AS rn, @c1 := CHAR1, @c2 := CHAR2, @c3 := CHAR3, @c4 := CHAR4, @c5 := CHAR5, @d := DATE FROM your_table, (SELECT @c1:='',@c2:='',@c3:='',@c4:='',@c5:='',@d:='',@group_rn:=0) init -- 按分组键倒序,组内第一条就是原升序的最后一条 ORDER BY CHAR1, CHAR2, CHAR3, CHAR4, CHAR5, DATE DESC ) tmp WHERE rn = 1;
避坑提示
- 不要使用要求将
NUMERIC加入分组维度的方案:这类方案本质是错误扩大了分组粒度,会把同组下NUMERIC值不同的行拆成独立分组,结果完全不符合预期。 - 多列分组不存在适配限制:只要把所有需要分组的维度字段按排序顺序写入分区/判断逻辑即可,不存在仅支持单列分组的问题。
- 若数据已经完成预排序,优先选择方案2,不需要做全表重排shuffle,大表下性能优势非常明显。
内容的提问来源于stack exchange,提问作者user19315317
相关产品推荐
相关产品推荐

