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

MySQL分组后非分组列折叠:如何控制显示的目标行?

在MySQL中分组后获取每组的顶部行

嗨,这个需求我在做用户订单、日志统计的时候经常碰到,下面给你分享几种实用的实现方式,分版本给你讲,方便你根据自己的MySQL版本选择:

一、MySQL 8.0+ 用窗口函数(最推荐)

MySQL 8.0之后支持窗口函数,这是处理这类分组取Top N场景最直观、最灵活的方式。常用的窗口函数有ROW_NUMBER()、RANK()、DENSE_RANK(),根据你对并列值的处理需求选就行:

1. 取每组唯一的顶部行(忽略并列)

比如我们有个orders表,要获取每个用户最新创建的订单(按order_date降序,即使有同一天的订单也只取其中一条):

SELECT user_id, order_date, order_amount
FROM (
    SELECT 
        user_id, 
        order_date, 
        order_amount,
        -- 按user_id分组,组内按order_date降序编序号
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_date DESC) AS row_num
    FROM orders
) AS ranked_orders
WHERE row_num = 1;

ROW_NUMBER()会给每组内的行按顺序分配唯一的序号,哪怕两行的order_date相同,序号也不一样,所以最终每组只会返回一行。

2. 保留并列的顶部行

如果想把同一用户下所有和最新日期相同的订单都返回,就用RANK()或者DENSE_RANK()替换ROW_NUMBER():

SELECT user_id, order_date, order_amount
FROM (
    SELECT 
        user_id, 
        order_date, 
        order_amount,
        RANK() OVER (PARTITION BY user_id ORDER BY order_date DESC) AS row_num
    FROM orders
) AS ranked_orders
WHERE row_num = 1;

比如同一个用户有两个订单在同一天,这两个订单的row_num都会是1,都会被筛选出来。

二、MySQL 5.7及以下版本(无窗口函数)

如果你的项目还在用老版本MySQL,也有两种靠谱的方法:

1. 关联查询法

思路是:对每一行数据,找同组内比它排序更靠前的行,如果找不到,那它就是组内的顶部行。还是以取最新订单为例:

SELECT o1.user_id, o1.order_date, o1.order_amount
FROM orders o1
LEFT JOIN orders o2 
    ON o1.user_id = o2.user_id 
    AND o1.order_date < o2.order_date -- 找同用户下日期更晚的订单
WHERE o2.user_id IS NULL; -- 找不到的话,o1就是最新的

这个方法会自动保留并列的顶部行,比如同一用户同一天的订单都会被返回。

2. GROUP BY + 子查询关联

先通过GROUP BY获取每组的最大(或最小)排序值,再关联原表取出对应的数据:

SELECT o.user_id, o.order_date, o.order_amount
FROM orders o
INNER JOIN (
    -- 先拿到每个用户的最新订单日期
    SELECT user_id, MAX(order_date) AS max_date
    FROM orders
    GROUP BY user_id
) AS latest_dates 
    ON o.user_id = latest_dates.user_id 
    AND o.order_date = latest_dates.max_date;

这个方法同样会返回所有符合最大日期的订单,适合需要保留并列值的场景。

一些小提示

  • 如果要取每组的最旧订单,只需要把排序方向改成ASC,或者把MAX()换成MIN()就行。
  • 窗口函数还能轻松实现取每组前N行,比如把WHERE row_num = 1改成WHERE row_num <= 3就能取每个用户的最新3条订单。
  • 老版本的方法记得给分组列和排序列加联合索引(比如INDEX idx_user_date (user_id, order_date)),不然数据量大的时候查询会很慢。

内容的提问来源于stack exchange,提问作者curiousgeorge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:18:02