赞
踩
开窗函数的语法结构:分析函数() over(partition by 分组列名 order by 排序列名 rows between 开始位置 and 结束位置)
over()函数中包括三个函数:分区partition by 列名、排序order by 列名、指定窗口范围rows between 开始位置 and 结束位置
rows between … and … 用得较少
我们知道聚合函数对一组值执行计算并返回单一的值,如sum(),count(),max(),min(), avg()等,这些函数常与group by子句连用。除 COUNT 外,聚合函数忽略空值。
但有时候一组数据只返回一组值是不满足需求的,如经常想知道各地区的前几名、各个班或各个学科的前几名。这时候需要每一组返回多个值。用开窗函数解决这类问题非常方便。它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行。
- DROP TABLE IF EXISTS temp
-
- CREATE TABLE temp(
- id INT,
- name VARCHAR(10),
- class VARCHAR(10),
- score INT
- );
-
- INSERT INTO temp (id, name, class, score) VALUES (1,'公孙衍', '2', 81);
- INSERT INTO temp (id, name, class, score) VALUES (2,'廉颇', '3', 55);
- INSERT INTO temp (id, name, class, score) VALUES (3,'李牧', '3', 55);
- INSERT INTO temp (id, name, class, score) VALUES (4,'王翦', '1', 96);
- INSERT INTO temp (id, name, class, score) VALUES (5,'王贲', '1', 92);
- INSERT INTO temp (id, name, class, score) VALUES (6,'白起', '1', 96);
- INSERT INTO temp (id, name, class, score) VALUES (7,'蔺相如', '3', 90);
- INSERT INTO temp (id, name, class, score) VALUES (8,'赵胜', '3', 81);
- INSERT INTO temp (id, name, class, score) VALUES (9,'赵雍', '3', 93);
- INSERT INTO temp (id, name, class, score) VALUES (10,'魏无忌', '2', 92);

实例:
无分组排序 | 分组排序(对班级) |
SELECT name,class,score, ROW_NUMBER() OVER(ORDER BY score DESC) mm FROM temp | SELECT name,class,score, ROW_NUMBER() OVER(PARTITION BY class ORDER BY score DESC) mm FROM temp |
![]() | ![]() |
- --也能用无分组无次序的排序实现,只是没有排序后的次序(也就是没有mm列)
- SELECT * FROM temp ORDER BY sroce DESC
实例:
查询每个班第一名的成绩 | 查询每个班最后一名的成绩 |
SELECT name,class,score FROM (SELECT name,class,score, RANK() OVER(PARTITION BY class ORDER BY score DESC) mm FROM TEMP ) a WHERE mm = 1; | SELECT name,class,score FROM ( SELECT name,class,score, RANK() OVER(PARTITION BY class ORDER BY score) mm FROM temp ) a WHERE mm = 1; |
![]() | |
在求第一名成绩时,不能用row_number(),因为如果同班有两个并列第一,mm=1就只返回一个结果。
不加desc,排序就默认升序,取mm=1,就是最后一名
排序,值一样不会重复排序。如1,2,3,4,5
排序,值一样重复排序,有间隙。如1,1,3,4
排序,值一样重复排序,没有间隙。如1,1,2,2,3,4,5
排序,分成2组。此函数一般用于取表中前百分之几的数据。如,取数据的前25%就将数据分4组,然后字段的条件是等于1。
lag和lead分析函数可以在同一次查询中,取出同一字段的前N行数据(lag)和 后N行数据(lead)作为独立的列。
在实际应用中,若要用到取今天和昨天的某字段差值时,lag和lead函数的应用就显得尤为重要。当然,这种操作可以用表的自连接实现,但lag和lead与left join、right join 等自连接相比,效率更高。
- lag(exp_str, offset, defval) over(partition by … order by …)
- lead(exp_str, offset, defval) over(partition by … order by …)
1、lag() 实例
- SELECT id,score,
- LAG(score,1,0)OVER() AS n1,
- LAG(score,1) OVER() AS n2,
- LAG(score,2,0)OVER() AS n6,
- LAG(score,2) OVER() AS n7
- FROM temp
2、lead() 实例
- SELECT id,score,
- LEAD(score,1,0)OVER() AS n1,
- LEAD(score,1) OVER() AS n2,
- LEAD(score,2,0)OVER() AS n6,
- LEAD(score,2) OVER() AS n7
- FROM temp
名称 | 描述 |
CUME_DIST() | 累计分配值 |
DENSE_RANK() | 当前行在其分区内的排名,没有间隙 |
FIRST_VALUE() | 窗口框架第一行的参数值 |
LAG() | 来自分区内滞后当前行的行的参数值 |
LAST_VALUE() | 窗口框架最后一行的参数值 |
LEAD() | 分区内行前导当前行的参数值 |
NTH_VALUE() | 来自第 N 行窗口框架的参数值 |
NTILE() | 其分区内当前行的桶数 |
PERCENT_RANK() | 百分比排名值 |
RANK() | 当前行在其分区内的排名,有间隙 |
ROW_NUMBER() | 其分区内的当前行数 |
group by是对检索结果的保留行进行单纯分组,一般和聚合函数一起使用。如max、min、sum、avg、count等一块用。 partition by虽然也具有分组功能,但同时也具有其他的高级功能。
sum() over()的使用
显示全部字段是为了方便查看,当有明确目标的时候可以适当选择相应字段。
SELECT t.*, SUM(t.score) s_sum FROM temp t GROUP BY t.class | SELECT t.*, SUM(t.score) OVER(PARTITION BY t.class ORDER BY t.score DESC) s_sum FROM TEMP t | SELECT t.*, SUM(t.score) OVER(ORDER BY t.id) s_sum FROM temp t |
![]() | ![]() | ![]() |
avg() over()的使用
SELECT id, score, AVG(score) OVER(ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM temp
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
限制计算移动平均值的范围,本语句包含本行和前两行。
语法总结:
avg(…A...) over(partition by …b… order by …C… rows between …D1… and …D2…)
sum(…A…) over(partition by …b… order by …C… rows between …D1… and …D2…)
窗口范围说明:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。