上一节我们已经明白了窗口函数到底有啥用。现在来看看具体的函数和它们的效果。语法细节我们下节再说。
ROW_NUMBER() 函数
ROW_NUMBER() 函数会给窗口里的每一行分配一个唯一的编号。就是按 ORDER BY 指定的顺序给每行排个号。
语法:
ROW_NUMBER() OVER ([PARTITION BY column] ORDER BY column)
解释一下:
PARTITION BY column(可选):把数据分组。如果不写,就是全表一起编号。ORDER BY column:指定按哪个字段排序来编号。
例子:给表里的行编号
来看一张 students 表,里面有学生和他们的分数。
SELECT * FROM students;
| id | name | score |
|---|---|---|
| 1 | Eva Lang | 95 |
| 2 | Maria Chi | 87 |
| 3 | Alex Lin | 78 |
| 4 | Anna Song | 95 |
| 5 | Otto Mart | 87 |
现在我们按分数(score)从高到低给每行排个号:
SELECT
name,
score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num
FROM students;
结果:
| name | score | row_num |
|---|---|---|
| Eva Lang | 95 | 1 |
| Anna Song | 95 | 2 |
| Maria Chi | 87 | 3 |
| Otto Mart | 87 | 4 |
| Alex Lin | 78 | 5 |
每一行都拿到了唯一的序号——而且是按分数从高到低排的。
这个操作其实很简单但很强大——直接在查询结果里加个行号。用传统 SELECT 根本做不到,必须用窗口函数才行。
RANK() 函数
RANK() 跟 ROW_NUMBER() 很像,但它会考虑相同的值。如果有几行排序字段一样,它们会拿到一样的排名,后面的排名会跳过。
语法:
RANK() OVER ([PARTITION BY column] ORDER BY column)
例子:按分数给学生排名
我们用 RANK() 来试试同样的数据:
SELECT
name,
score,
RANK() OVER (ORDER BY score DESC) AS rank
FROM students;
结果:
| name | score | rank |
|---|---|---|
| Eva Lang | 95 | 1 |
| Anna Song | 95 | 1 |
| Maria Chi | 87 | 3 |
| Otto Mart | 87 | 3 |
| Alex Lin | 78 | 5 |
这里分数一样的行(95 和 87)拿到一样的排名,后面的排名就跳过了。
DENSE_RANK() 函数
DENSE_RANK() 跟 RANK() 差不多,但排名不会跳号。也就是说有重复的行,后面的排名只会加 1。
语法:
DENSE_RANK() OVER ([PARTITION BY column] ORDER BY column)
例子:紧密排名
我们用 DENSE_RANK() 试试同样的数据:
SELECT
name,
score,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank
FROM students;
结果:
| name | score | dense_rank |
|---|---|---|
| Eva Lang | 95 | 1 |
| Anna Song | 95 | 1 |
| Maria Chi | 87 | 2 |
| Otto Mart | 87 | 2 |
| Alex Lin | 78 | 3 |
这里和 RANK() 不一样,排名是连续的,没有跳号。
NTILE() 函数
NTILE() 会把行分成 n 个均匀的组(分位),每行分到一个组里。
语法:
NTILE(n) OVER ([PARTITION BY column] ORDER BY column)
n:你想分成几组。
例子:把学生分成 3 组
我们把学生按分数从高到低分成 3 组:
SELECT
name,
score,
NTILE(3) OVER (ORDER BY score DESC) AS group_num
FROM students;
结果:
| name | score | group_num |
|---|---|---|
| Eva Lang | 95 | 1 |
| Anna Song | 95 | 1 |
| Maria Chi | 87 | 2 |
| Otto Mart | 87 | 2 |
| Alex Lin | 78 | 3 |
注意:如果不能完全均分,多出来的行会优先分到前面的组。比如这里前两组各有两个人,最后一组只有一个。
什么时候用哪个函数?
ROW_NUMBER():想给每行唯一编号时用,按排序顺序来。RANK():需要考虑相同值排名,并且允许排名跳号时用。DENSE_RANK():考虑相同值排名,但排名不跳号时用。NTILE():想把行均匀分组时用。
这些函数能让你分析数据的方式直接升级。只要你需要灵活地给数据编号或者分组,窗口函数都能帮上大忙。
GO TO FULL VERSION