平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“PostgreSQL中rank()窗口函数实用指南与示例”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
rank()是一个窗口函数,用来计算结果集中每一行的排名。它的基本语法如下所示:
rank() OVER ([PARTITION BY partition_expression] ORDER BY order_expression)
特点:
假设有一个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_name | department | salary | dept_salary_rank |
|---|---|---|---|
| Frank | IT | 62000 | 1 |
| David | IT | 60000 | 2 |
| Bob | Marketing | 55000 | 1 |
| Eve | Marketing | 55000 | 1 |
| Charlie | Sales | 52000 | 1 |
| Alice | Sales | 50000 | 2 |
解释:
场景:找出每个类别中最贵的两个产品。
示例数据:
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 rank
FROM
products
) ranked
WHERE rank <= 2;
结果:
| product_id | category | price | rank |
|---|---|---|---|
| 1 | A | 100 | 1 |
| 2 | A | 80 | 2 |
| 3 | B | 200 | 1 |
| 4 | B | 180 | 2 |
| 6 | C | 120 | 1 |
解释:
场景:计算每个学生的成绩百分位。
示例数据:
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;
结果:
| student | score | rank | percentile |
|---|---|---|---|
| Student 3 | 78 | 1 | 20.00 |
| Student 1 | 85 | 2 | 40.00 |
| Student 5 | 88 | 3 | 60.00 |
| Student 4 | 90 | 4 | 80.00 |
| Student 2 | 92 | 5 | 100.00 |
解释:
PostgreSQL提供了多个窗口函数用来排名,各有特点:
| 函数 | 描述 |
|---|---|
| rank() | 相同值的行获得相同排名,下一个排名跳过相同值的数量。 |
| dense_rank() | 相同值的行获得相同排名,下一个排名不跳过,保持连续。 |
| row_number() | 每行分配唯一的序号,不考虑相同值,即使值相同也会分配不同序号。 |
示例数据:
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;
结果:
| player | score | rank | dense_rank |
|---|---|---|---|
| Player 1 | 100 | 1 | 1 |
| Player 2 | 95 | 2 | 2 |
| Player 3 | 95 | 2 | 2 |
| Player 4 | 90 | 4 | 3 |
解释:
rank()在遇到相同分数时跳过了排名3。dense_rank()在遇到相同分数时不跳过排名,保持连续。场景:为每日的销售记录分配唯一序号,按销售金额降序排列。
示例数据:
WITH sales AS (
SELECT
DATE '2023-01-01' AS sale_date,
1000 AS amount
UNION ALL
SELECT
DATE '2023-01-01',
1500
UNION ALL
SELECT
DATE '2023-01-02',
1200
UNION ALL
SELECT
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_date | amount | row_num |
|---|---|---|
| 2023-01-01 | 1500 | 1 |
| 2023-01-01 | 1000 | 2 |
| 2023-01-02 | 1200 | 1 |
| 2023-01-02 | 1200 | 2 |
解释:
row_number()也会为每条记录分配唯一的序号。采用窗口函数如rank()时,可能会对查询性能产生影响,尤其是在处理大数据集时。以下是一些优化建议:
ORDER BY子句明确,避免全表排序带来的性能开销。ORDER BY和PARTITION BY涉及的列上新建索引,能够加快排序和分区操作。WHERE rank <= N能够减少计算量。PostgreSQL的rank()窗口函数是一个强大的工具,适用来各种排名需求,如部门内薪资排名、每组Top N记录、百分位数计算等。借助合理采用rank()及其相关函数(如dense_rank()和row_number()),能够高效地处理复杂的数据分析任务。
关键点回顾:
rank()函数为相同值的行分配相同的排名,同时跳过后续排名。PARTITION BY和ORDER BY,能够完成多层次的排名需求。dense_rank()和row_number())相比,rank()在处理同时列排名时有独特的行为。落到代码里,希望本文的示例和解释能帮助你在实际项目中更好地应用rank()函数,提升数据处理的效率和准确性!
到此这篇关于PostgreSQL中rank()窗口函数实用指南与示例的文章就介绍到这了,更多相关PostgreSQL rank()窗口函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多兼容脚本之家!
tplink5620与6300区别是什么(tplink5620与6300区别详解)
tplink路由器无线信道选哪个好(tplink路由器无线信道选择推荐)
tplink百兆路由器怎么改成千兆(tplink百兆路由器改成千兆方法)
tplink百兆路由器哪个好(tplink百兆路由器选择推荐)
postgres 数据库迁移的几种做法实用指南
PostgreSQL中rank()窗口函数实用指南与示例实用指南