PostgreSQL中的rank()窗口函数:实用指南与示例

在数据分析和数据库管理中,经常需要对数据进行排名操作。PostgreSQL提供了强大的窗口函数rank(),可以方便地对结果集中的行进行排名。本文将详细介绍rank()函数的使用方法,并通过多个实用示例展示其在不同场景下的应用。

一、rank()函数简介

rank()是一个窗口函数,用于计算结果集中每一行的排名。它的基本语法如下:

rank() OVER ([PARTITION BY partition_expression] ORDER BY order_expression)
  • PARTITION BY:可选子句,用于将结果集划分为多个分区,排名在每个分区内独立计算。
  • ORDER BY:指定排名的顺序依据。

特点

  • 相同值的行会获得相同的排名。
  • 下一个排名会跳过相同值的数量。例如,如果有两个第一名,下一个排名是第三名。

二、基础示例:部门内员工薪资排名

假设有一个employees表,包含员工姓名、部门和薪资信息。我们希望计算每个部门内员工的薪资排名。

示例数据

首先,创建示例数据:

WITH sample_data AS (SELECT * FROM (VALUES ('Alice', 'Sales', 50000),('Bob', 'Marketing', 55000),('Charlie', 'Sales', 52000),('David', 'IT', 60000),('Eve', 'Marketing', 55000),('Frank', 'IT', 62000)) AS t(employee_name, department, salary)
)

排名查询

使用rank()函数按部门分区,按薪资降序排名:

SELECT employee_name, department, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_salary_rank
FROM sample_data
ORDER BY department, dept_salary_rank;

结果

employee_namedepartmentsalarydept_salary_rank
FrankIT620001
DavidIT600002
BobMarketing550001
EveMarketing550001
CharlieSales520001
AliceSales500002

解释

  • 在IT部门,Frank薪资最高,排名为1;David次之,排名为2。
  • 在Marketing部门,Bob和Eve薪资相同,均排名为1。
  • 在Sales部门,Charlie薪资最高,排名为1;Alice次之,排名为2。

三、高级应用示例

1. 每组Top N记录

场景:找出每个类别中最贵的两个产品。

示例数据

WITH products AS (SELECT * FROM (VALUES (1, 'A', 100),(2, 'A', 80),(3, 'B', 200),(4, 'B', 180),(5, 'B', 150),(6, 'C', 120)) AS t(product_id, category, price)
)

查询

SELECT * 
FROM (SELECT product_id, category, price, RANK() OVER (PARTITION BY category ORDER BY price DESC) AS rankFROM products
) ranked
WHERE rank <= 2;

结果

product_idcategorypricerank
1A1001
2A802
3B2001
4B1802
6C1201

解释

  • 每个类别中,价格最高的前两个产品被筛选出来。

2. 百分位数计算

场景:计算每个学生的成绩百分位。

示例数据

WITH scores AS (SELECT * FROM (VALUES ('Student 1', 85),('Student 2', 92),('Student 3', 78),('Student 4', 90),('Student 5', 88)) AS t(student, score)
)

查询

SELECT student, score, RANK() OVER (ORDER BY score) AS rank,ROUND(100.0 * RANK() OVER (ORDER BY score) / (SELECT COUNT(*) FROM scores), 2) AS percentile
FROM scores;

结果

studentscorerankpercentile
Student 378120.00
Student 185240.00
Student 588360.00
Student 490480.00
Student 2925100.00

解释

  • 百分位数通过排名除以总记录数并乘以100计算得出。

四、rank()与其他窗口函数的比较

PostgreSQL提供了多个窗口函数用于排名,各有特点:

函数描述
rank()相同值的行获得相同排名,下一个排名跳过相同值的数量。
dense_rank()相同值的行获得相同排名,下一个排名不跳过,保持连续。
row_number()每行分配唯一的序号,不考虑相同值,即使值相同也会分配不同序号。

示例:rank() vs dense_rank()

示例数据

WITH scores AS (SELECT * FROM (VALUES ('Player 1', 100),('Player 2', 95),('Player 3', 95),('Player 4', 90)) AS t(player, score)
)

在这里插入图片描述

查询

SELECT player, score, RANK() OVER (ORDER BY score DESC) AS rank,DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank
FROM scores;

结果

playerscorerankdense_rank
Player 110011
Player 29522
Player 39522
Player 49043

解释

  • rank()在遇到相同分数时跳过了排名3。
  • dense_rank()在遇到相同分数时不跳过排名,保持连续。

示例:row_number()

场景:为每日的销售记录分配唯一序号,按销售金额降序排列。

示例数据

WITH sales AS (SELECT DATE '2023-01-01' AS sale_date, 1000 AS amountUNION ALLSELECT DATE '2023-01-01', 1500UNION ALLSELECT DATE '2023-01-02', 1200UNION ALLSELECT DATE '2023-01-02', 1200
)

查询

SELECT sale_date, amount, ROW_NUMBER() OVER (PARTITION BY sale_date ORDER BY amount DESC) AS row_num
FROM sales;

结果

sale_dateamountrow_num
2023-01-0115001
2023-01-0110002
2023-01-0212001
2023-01-0212002

解释

  • 即使同一天有相同的销售金额,row_number()也会为每条记录分配唯一的序号。

五、性能优化建议

使用窗口函数如rank()时,可能会对查询性能产生影响,尤其是在处理大数据集时。以下是一些优化建议:

  1. 使用PARTITION BY合理分区:将数据划分为较小的分区,可以减少每个窗口函数计算的数据量。
  2. 指定ORDER BY明确排序:确保ORDER BY子句明确,避免全表排序带来的性能开销。
  3. 创建适当的索引:在ORDER BYPARTITION BY涉及的列上创建索引,可以加快排序和分区操作。
  4. 限制结果集:如果只需要前N条记录,结合WHERE rank <= N可以减少计算量。

六、总结

PostgreSQL的rank()窗口函数是一个强大的工具,适用于各种排名需求,如部门内薪资排名、每组Top N记录、百分位数计算等。通过合理使用rank()及其相关函数(如dense_rank()row_number()),可以高效地处理复杂的数据分析任务。

关键点回顾

  • rank()函数为相同值的行分配相同的排名,并跳过后续排名。
  • 结合PARTITION BYORDER BY,可以实现多层次的排名需求。
  • 与其他窗口函数(如dense_rank()row_number())相比,rank()在处理并列排名时有独特的行为。
  • 通过优化查询和索引,可以提升窗口函数的性能表现。

希望本文的示例和解释能帮助你在实际项目中更好地应用rank()函数,提升数据处理的效率和准确性!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/910707.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习设计模式《十六》——策略模式

一、基础概念 策略模式的本质是【分离算法&#xff0c;选择实现】。 策略模式的定义&#xff1a;定义一系列的算法&#xff0c;把它们一个个封装起来&#xff0c;并且使他们可以相互替换。本模式使得算法可独立于使用它的客户而变化。 策略模式的上下文&#xff08;context&…

Stereolabs ZED系列与ZED X立体相机系列对比:如何根据项目需求选择?

Stereolabs是全球领先的三维视觉技术公司&#xff0c;专注于为机器人、自动化和空间感知等领域提供高性能视觉解决方案。其ZED立体相机系列包括ZED和ZED X两大系列&#xff0c;分别针对多场景三维感知和工业级应用设计&#xff0c;为企业和开发者提供了丰富的选择。 ZED系列&am…

人体属性识别+跌倒检测:儿童行为监测与安全升级

智慧幼儿园的AI智能检测盒应用实践 背景&#xff1a;传统园区管理的三大痛点 传统幼儿园管理长期面临三大核心挑战&#xff1a;一是安全监控依赖人工巡查&#xff0c;存在视觉盲区与响应延迟&#xff0c;如某连锁幼儿园曾因人工巡查疏漏&#xff0c;导致3起儿童跌倒事故未能及…

简单聊聊 Flutter 在鸿蒙上为什么可以 hotload ?

众所周知&#xff0c; Flutter 最大的特色之一就是 Debug 过程中支持 hotload &#xff0c;不错的 hotload 体验对于开发效率十分重要&#xff0c;而在此之前&#xff0c;我们在 《Flutter 又双叒叕可以在 iOS 26 的真机上 hotload》 聊过了 Flutter 和 iOS 在 hotload 上的爱恨…

深度学习原理与Pytorch实战

深度学习原理与Pytorch实战 第2版 强化学习人工智能神经网络书籍 python动手学深度学习框架书 TransformerBERT图神经网络&#xff1a; 技术讲解 编辑推荐 1.基于PyTorch新版本&#xff0c;涵盖深度学习基础知识和前沿技术&#xff0c;由浅入深&#xff0c;通俗易懂&#xf…

发布/订阅模式:解耦系统的强大设计模式

Hi&#xff0c;我是布兰妮甜 &#xff01;发布/订阅模式&#xff08;Publish/Subscribe Pattern&#xff0c;简称 Pub/Sub&#xff09;是一种消息传递模式&#xff0c;它允许发送者&#xff08;发布者&#xff09;将消息发送给多个接收者&#xff08;订阅者&#xff09;&#x…

前端开发面试题总结-原生小程序部分

文章目录 1、wxss和css的区别?2、原生小程序组件使用过哪些?3、原生小程序中如何绑定事件?4、原生小程序中如何修改数据并同步视图?5、原生小程序中如何进行事件传参?6、小程序中发起网络请求7、 导航跳转方式?8、 监听上拉触底和下拉刷新?9、 小程序的生命周期函数?10…

WPS会员享受权益集锦

也许你经常使用WPS&#xff0c;但可能不了解究竟有哪些功能只有会员才能享受呢&#xff0c;作为一个经常使用WPS会员办公的老师&#xff0c;我今天就给你分类理一理&#xff1a;我把WPS会员功能进行分类整理&#xff0c;按功能属性划分为以下六大类&#xff1a; 一、云存储与管…