SQL 如何实现分组内排序?

使用窗口函数ROW_NUMBER()、RANK()或DENSE_RANK()配合PARTITION BY实现分组内排序,保留每行记录;如查各部门工资前3员工:SELECT * FROM (SELECT name,dept,salary,ROW_NUMBER() OVER(PARTITION BY dept ORDER BY salary DESC) AS rn FROM employees) t WHERE rn

sql 如何实现分组内排序?

SQL 实现分组内排序,主要靠窗口函数 ROW_NUMBER()RANK()DENSE_RANK() 配合 PARTITION BY 子句,而不是用 GROUP BY —— 因为 GROUP BY 会聚合数据,无法保留每行原始记录来排序。

用 PARTITION BY + 排序窗口函数

这是最常用、最直接的方式:按指定字段分组,在每组内部按另一字段排序,并为每行生成序号。

  • PARTITION BY 定义分组依据(类似 GROUP BY 的分组逻辑,但不压缩行)
  • ORDER BY 写在窗口函数中,决定组内排序规则
  • 例如:查每个部门工资最高的前 3 名员工

SELECT * FROM (
  SELECT name, dept, salary,
      ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
  FROM employees
) t WHERE rn

ROW_NUMBER vs RANK vs DENSE_RANK 的区别

三者都支持分组内排序,但处理并列的方式不同:

  • ROW_NUMBER():严格按顺序编号,相同值也分配不同序号(1,2,3,4…)
  • RANK():并列时给相同序号,跳过后续位次(1,2,2,4…)
  • DENSE_RANK():并列时给相同序号,不跳位次(1,2,2,3…)

比如某部门三人薪资为 15000、12000、12000:
ROW_NUMBER → 1,2,3;RANK → 1,2,2;DENSE_RANK → 1,2,2

配合 WHERE 或子查询筛选分组内 Top-N

窗口函数不能直接在 WHERE 中使用(因为执行顺序晚于 WHERE),必须嵌套子查询或 CTE:

站长俱乐部购物系统

站长俱乐部购物系统

功能介绍:1、模块化的程序设计,使得前台页面设计与程序设计几乎完全分离。在前台页面采用过程调用方法。在修改页面设计时只需要在相应位置调用设计好的过程就可以了。另外,这些过程还提供了不同的调用参数,以实现不同的效果;2、阅读等级功能,可以加密产品,进行收费管理;3、可以完全可视化编辑文章内容,所见即所得;4、无组件上传文件,服务器无需安装任何上传组件,无需支持FSO,即可上传文件。可限制文件上传的类

下载

  • 写法一:用子查询包裹,外层加 WHERE 过滤序号
  • 写法二:用 CTE 更清晰(尤其多步计算时)
  • 注意:ORDER BY 在窗口函数里只影响排序逻辑,不影响最终结果集顺序;如需整体有序,外层再加 ORDER BY

WITH ranked AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY category ORDER BY score DESC) AS seq
  FROM products
)
SELECT name, category, score FROM ranked WHERE seq = 1;

旧版本 MySQL(

只能用自连接或相关子查询模拟,性能较差,且逻辑复杂:

  • 自连接:对每行统计同组中比它大的记录数,+1 即为名次
  • 示例(找每科最高分学生):对 scores 表,按 subject 分组,用 LEFT JOIN 找出“没有更高分”的记录
  • 建议升级到 MySQL 8.0+ 或 PostgreSQL / SQL Server 等原生支持窗口函数的数据库

不复杂但容易忽略:分组内排序本质是“每行独立计算位置”,不是聚合,所以别用 GROUP BY 去尝试实现。

https://www.php.cn/faq/2010277.html

发表回复

Your email address will not be published. Required fields are marked *