row_number() over (partition by …) 是 sql 中用于在分组内生成唯一序号的窗口函数。1. row_number() 生成行号;2. over() 标识窗口函数范围;3. partition by 按指定字段分组,类似 group by 但不合并行;4. order by 定义组内排序方式。常见用途包括分组排名(如按销售人员分组后按销售额排序)、去重(如保留每个用户最新日志)。使用时需注意正确选择分区字段和排序方向,编号始终唯一且连续,适用于筛选、排名等场景。
在 SQL 中,ROW_NUMBER() OVER (PARTITION BY …) 是一个非常实用的窗口函数,常用于给数据分组后编号。它的核心作用是:在指定的分区(分组)内,为每一行数据生成一个唯一的序号,从 1 开始递增。
比如你有一张销售记录表,想看看每个销售人员按销售额从高到低的排名,这时候就可以用它来编号。
如何理解 ROW_NUMBER() OVER (PARTITION BY …)
这个语法结构分为几个部分:
- ROW_NUMBER():生成行号。
- OVER():表示这是一个窗口函数。
- PARTITION BY column_name:按照某个字段进行分组,类似 GROUP BY,但不会合并行。
- ORDER BY column_name:在每个分区内按什么顺序编号。
举个例子:
SELECT salesperson, sale_date, amount, ROW_NUMBER() OVER (PARTITION BY salesperson ORDER BY amount DESC) AS rank FROM sales;
这段 SQL 的意思是:按销售人员分组,每组内部按销售额从高到低排序,并给每条记录打上编号。
常见使用场景
分组排名
最常见的用途就是做排名。比如你要看每位员工每月的业绩排名,就可以这样写:
ROW_NUMBER() OVER (PARTITION BY employee_id, month ORDER BY performance_score DESC)
这样就能看到每个人每个月的排名情况。
去重保留最新或最旧的一条
有时候你会遇到重复数据,比如同一用户有多条记录,你想只取最新的那一条。可以用 ROW_NUMBER() 配合子查询实现:
WITH ranked_data AS ( SELECT user_id, log_time, action, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY log_time DESC) AS rn FROM user_logs ) SELECT * FROM ranked_data WHERE rn = 1;
这里的意思是:每个用户按时间倒序排,取第一条数据,也就是最近的一条日志。
使用时需要注意的细节
- 分区字段要选对:PARTITION BY 后面的字段决定了你怎么分组。如果漏了关键字段,结果可能完全不对。
- 排序方式影响编号顺序:默认升序排,ASC 是从小到大,DESC 是从大到小。根据业务需要选择合适的排序方式。
- 编号不唯一:虽然叫 ROW_NUMBER(),但其实它是严格按排序生成的连续整数,不会有重复值,这点和 RANK()、DENSE_RANK() 不一样。
总结一下
ROW_NUMBER() OVER (PARTITION BY …) 就是用来在分组内编号的工具,特别适合做排名、去重、筛选等操作。只要搞清楚怎么分组、怎么排序,基本就能用好了。
基本上就这些,不复杂但容易忽略的地方在于分区字段和排序方向的选择,多练几次就熟悉了。