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

基于多列分组选取每组最后一条观测并保留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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:06:21