mysql分组排序怎么查

来源:站长素材作者:湖南程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《mysql分组排序怎么查》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《mysql分组排序怎么查》有用,将其分享出去将是对创作者最好的鼓励。

在mysql的查询场景中,分组排序是指先按照指定字段对数据进行分组,再在每个分组内部按照某个规则对数据排序,这种需求在数据统计分析、组内TopN查询等场景中非常常见。实现分组排序可以根据mysql的版本选择不同的方案,低版本可以使用子查询配合排序实现,高版本可以直接使用窗口函数完成。

mysql分组排序怎么查

方法一:使用窗口函数实现分组排序

mysql 8.0及以上版本支持窗口函数,其中ROW_NUMBER()RANK()DENSE_RANK()都可以配合PARTITION BYORDER BY实现分组排序,三者的主要区别是处理并列排名的逻辑不同。

常用窗口函数说明

  • ROW_NUMBER():每个分组内按顺序生成连续唯一的序号,即使排序字段值相同,序号也不会重复
  • RANK():排序字段值相同的行序号相同,下一个序号会跳过重复的数量,比如两个第1,下一个就是第3
  • DENSE_RANK():排序字段值相同的行序号相同,下一个序号连续,比如两个第1,下一个就是第2

示例代码

假设有一张学生成绩表student_score,结构如下:

字段名类型说明
idint记录ID
class_idint班级ID
student_namevarchar(50)学生姓名
scoreint考试成绩

需求是按班级分组,每个班级内按成绩从高到低排序,生成每个学生的班级内排名,使用ROW_NUMBER()实现的sql如下:

-- 按班级分组,组内按成绩降序排序,生成连续排名
SELECT 
    class_id,
    student_name,
    score,
    ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS class_rank
FROM student_score;

如果需要并列排名不跳过序号,把ROW_NUMBER()替换成DENSE_RANK()即可:

-- 按班级分组,组内按成绩降序排序,生成连续不跳号的并列排名
SELECT 
    class_id,
    student_name,
    score,
    DENSE_RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS class_rank
FROM student_score;

方法二:低版本mysql使用子查询实现分组排序

如果mysql版本低于8.0,不支持窗口函数,可以通过子查询的方式实现分组排序,核心思路是给每个分组内的数据手动计算排序序号。

同样以上面的学生成绩表为例,实现按班级分组、组内按成绩降序排序的需求,sql如下:

-- 低版本mysql实现分组排序,通过子查询计算组内排名
SELECT 
    t1.class_id,
    t1.student_name,
    t1.score,
    (SELECT COUNT(*) + 1 
     FROM student_score t2 
     WHERE t2.class_id = t1.class_id 
       AND t2.score > t1.score) AS class_rank
FROM student_score t1
ORDER BY t1.class_id, t1.score DESC;

这段sql的逻辑是,对于t1表中的每一行数据,去t2表中查询同一个班级内成绩比当前行高的记录数量,数量加1就是当前行的组内排名。如果成绩相同,排名也会相同,不过这种方式性能比窗口函数差,数据量大的时候不建议使用。

分组排序取TopN的场景

很多时候分组排序的需求是取每个组内的前N条数据,比如取每个班级的前3名,使用窗口函数的实现方式如下:

-- 取每个班级成绩前3名的学生
WITH ranked_score AS (
    SELECT 
        class_id,
        student_name,
        score,
        ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS class_rank
    FROM student_score
)
SELECT class_id, student_name, score, class_rank
FROM ranked_score
WHERE class_rank <= 3;

低版本mysql实现每个班级前3名的查询如下:

-- 低版本mysql取每个班级成绩前3名
SELECT t1.*
FROM student_score t1
WHERE (
    SELECT COUNT(*) 
    FROM student_score t2 
    WHERE t2.class_id = t1.class_id 
      AND t2.score > t1.score
) < 3
ORDER BY t1.class_id, t1.score DESC;

注意事项

  • 使用GROUP BY分组的时候,如果直接配合ORDER BY,排序是对整个结果集排序,不是对分组内排序,不要混淆这个逻辑
  • 窗口函数中的PARTITION BY才是用来指定分组字段的,ORDER BY才是分组内的排序规则
  • 如果分组内排序的字段有NULL值,mysql会默认把NULL值排在最前面,如果需要调整NULL值的排序位置,可以在ORDER BY后面加IS NULL判断,比如ORDER BY score IS NULL, score DESC,这样NULL值会排在最后
  • 数据量较大的时候优先使用窗口函数实现分组排序,性能远优于子查询的方式

mysql分组排序group_byorder_by窗口函数修改时间:2026-07-02 11:57:39

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。