SQL中如何获取每个分组中字段值排名前三的记录?

落强吖_5082

落强吖_5082

2026-07-19

722人浏览

原创

使用 row_number() 配合 partition by 可实现分组 top 3:先按分组维度分区、组内按指定字段降序排序并编号,再在外层筛选 rn ≤ 3 的记录。

sql中如何获取每个分组中字段值排名前三的记录?

用 ROW_NUMBER() 配合 PARTITION BY 实现分组 Top 3

直接上最常用也最可控的解法:窗口函数 ROW_NUMBER()。它按分组内排序生成连续整数,不会跳过重复值,适合“取前 3 条”这种明确数量的需求。

关键点在于:PARTITION BY 定义分组维度,ORDER BY 决定组内排序依据(比如按销售额降序),再用外层查询过滤 rn 。

  • 示例(MySQL 8.0+ / PostgreSQL / SQL Server / Oracle):
SELECT *
FROM (
  SELECT *,
         ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rn
  FROM orders
) t
WHERE rn 
  • category 是分组字段,sales 是排序字段,可替换成你实际的列名
  • 注意:如果同一组内有多个记录 sales 相同,ROW_NUMBER() 会强制给它们不同排名(比如 1、2、3、4),可能把本该并列第 3 的记录挤出去
  • 若需保留并列情况(如两个第 2 名后直接第 4 名),改用 RANK() 或 DENSE_RANK(),但要小心结果条数可能超过 3

RANK() 和 DENSE_RANK() 的区别在哪?什么时候该换用?

当业务要求“并列也算名额”时,ROW_NUMBER() 就不合适了。比如某组销售前三名是 100、95、95、90,你希望取出 4 条记录(两个第 2 名 + 第 3 名),就得选 RANK()。

莓图AI
莓图AI

莓图AI是一款AI文本写作工具,专注于AI图片生成与视觉风格复刻的智能创作平台。

下载
  • RANK():并列时跳过后续名次(1,2,2,4)→ 可能返回 >3 行
  • DENSE_RANK():并列不跳号(1,2,2,3)→ 更贴近“实际名次感”,但同样可能超 3 行
  • 如果必须严格限制为最多 3 行,且允许并列,则只能用 RANK() + 外层加额外逻辑(比如取 rank 后再按主键去重或截断)
  • MySQL 5.7 或更早版本不支持窗口函数,得用自关联或变量模拟,性能差、易出错,建议升级或换方案

旧版 MySQL(

没有 ROW_NUMBER() 时,常见做法是用相关子查询数“当前记录在组内排第几”,但数据量一大就明显变慢。

SELECT o1.*
FROM orders o1
WHERE (
  SELECT COUNT(*)
  FROM orders o2
  WHERE o2.category = o1.category
    AND o2.sales > o1.sales
) 
  • 核心逻辑:统计同组中比当前记录 sales 更高的数量,小于 3 即说明是 Top 3
  • 注意:这里用的是 而不是 <code>,因为 COUNT 从 0 开始计数(最高者 COUNT=0)
  • 性能隐患极大:每行都触发一次子查询,10 万行数据可能变成千万级扫描
  • 如果表有复合索引 (category, sales),能显著加速,否则慎用

GROUP BY 不能直接配合 LIMIT 实现分组 Top N

有人试过写 GROUP BY category LIMIT 3,发现只返回 3 条总记录,不是每组 3 条——这是常见误解。

  • GROUP BY 是聚合操作,LIMIT 作用于最终结果集,不是每个分组
  • 试图用 GROUP_CONCAT() 拼接再解析,既难维护又无法保留原始字段结构
  • 真正需要“每组 Top N”时,窗口函数是唯一干净解法;没窗口函数就只能接受性能妥协或应用层处理

真正麻烦的不是语法,而是想清楚“并列怎么算”和“数据量是否扛得住子查询”。这两点没理清,再漂亮的 SQL 也可能上线就卡住。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4503

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

931

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1189

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6481

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3263

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6440

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

8801

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1190

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1052

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PDO数据库抽象层
PDO数据库抽象层

共7课时 | 3.3万人学习

SQL优化与排查(MySQL版)
SQL优化与排查(MySQL版)

共26课时 | 3.3万人学习