sql 中 row_number over partition by 用法_sql 中 row_number 分区编号详解

说实话,当我第一次接触SQL时,我对ROW_NUMBER感到困惑很长一段时间。
我记得第一次在项目中使用它时,我想根据每月的绩效对某个销售团队进行排名。
结果我写的SQL花了很长时间,最终发现ORDER BY后面的字段是错误的。

当时,我们有一个表叫Sales,里面存储了每个销售员每天销售的商品数量。
我写了一条SQL,看看每个供应商的月业绩从高到低在哪里,所以我是这样写的:
SQL 选择供应商、销售日期、金额、 ROW_NUMBER() OVER(按供应商分区,月份(sale_date) 按十二生肖排序 (DESC) AS 排名 来自销售 其中年份(销售日期)= 2 02 3 年,月份(销售日期)= 3 ;
说实话,一开始我不明白为什么要在 PARTITION BY 中添加 MONTH(sale_date)。
随后,老板指着报告说:“你看,张三三月份的销量最好,但李四可能四月份就超过了他,我们得按月比较。
”这时候我才明白PARTITION BY不仅仅是分组,而是将数据分成多个堆,然后每个堆独立编号。

最烦人的是order by。
想一想,如果业绩好的人排在第一位,那么每个销售人员在3 月份的最高销售额记录就会排在第一位。
但是如果表中有负数的记录(比如退货?),就会一直运行到最后。
为了将退货记录移回原处,我在 ORDER BY 中添加了 CASE WHEN amount < 0>结果,随着数据量的增加,服务器崩溃了。
运维小哥说:“兄弟,你的SQL太重了。
”后来我发现只使用 amount DESC 就足够了,因为负数是最小的。

一个有趣的场景是处理用户日志重复数据删除。
例如,有一个系统日志表。
用户A每小时可能会刷新页面数十次。
如果我们想要每小时获得每个用户的最新记录,我们可以这样做:
sql 与rank_log AS( 选择用户 ID、日志时间、操作、 ROW_NUMBER() OVER(按 user_id 分区,DATE_TRUNC('hour', log_time) ORDER BY log_time DESC) AS RN 来自用户日志 ) 选择用户 ID、日志时间、操作 来自rank_log 其中 rn=1 ;
我个人没有在这方面运行过PostgreSQL的DATE_TRUNC,但我应该记得影响是在X左右,但我建议你检查一下时区问题。
关键是PARTITION BY中添加了DATE_TRUNC('hour', log_time),这样可以将同一小时的记录分为一组,然后按log_time降序排序。
rn=1 的就是最新的。

ROW_NUMBER 最烦人的一点是它产生的数字严格加 1 ,即使组中只有一条记录。
我曾经写过一份报告,想看前N个销售人员,结果发现只有一个销售人员,而且居然直接显示了第N+1 个销售人员。
后来,我开始使用 RANK() 函数。
给了它,我再也不用面对这种损失了。

现在我已经习惯使用ROW_NUMBER,但是当我第一次开始使用它时,我实际上必须逐行调试数据。
想一想,PARTITION BY是入栈,ORDER BY是排序,然后编号。
当这三者结合起来时,出错的可能性就会变得更大。
我有一个同事把 PARTITION BY 和 ORDER BY 写反了,结果排名完全混乱了。
他急得满头大汗,最终发现少了一个逗号。

归根结底,ROW_NUMBER是一个强大的工具,用于解决“组内排名”等问题。
主要是要区分:如何创建组(通过分区)以及如何在组内排序(通过排序)。
练习得越多,您在选择分区字段和排序方向方面就会越熟练。

保姆级教你使用SQL窗口函数- ROW_NUMBER