窗口函数-分组排序:row_number()、rank() 、dense_rank()、ntile()

窗口函数语法结构:

分析函数() over(partition by 分组列名 order by 排序列名 rows between 开始位置 and 结束位置)

开窗函数和聚合函数区别:

聚合函数会对一组值进行计算并返回一个值,常见的比如sum(),count(),max(),min(), avg(),会与group by一起使用。

注意其中只有count不忽略null值,COUNT(a):返回非空值的数量。COUNT(*):返回所有行的数量(不区分空值)。

count(0)=1

ROW_NUMBER()

有些场景比如求各个班或各个学科的前几名,这时候需要每一组返回多个值,就需要开窗函数解决。

比如现在有一部分学生成绩,来自不同的班级:

求所有人中的前几名学生:

首先想到SELECT * FROM temp ORDER BY sroce DESC 这是对分数倒序排序,如果想只要前几名名,需要生成一个序号,所以使用ROW_NUMBER()。不分组

sql 复制代码
SELECT name,class,score, ROW_NUMBER() OVER(ORDER BY score DESC) mm FROM temp

如果对于班级分组 加上PARTITION BY class

sql 复制代码
SELECT name,class,score 
FROM ( 
	SELECT name,class,score, 
		RANK() OVER(PARTITION BY class ORDER BY score) mm 
		FROM temp 
	) a 
	WHERE mm = 1;

--这里引用博客:[窗口函数over] (https://blog.csdn.net/qq_55342245/article/details/122300899)的例子

RANK() DENSE_RANK()

进一步,如果只要第一名,或者最后一名就不能用row_number(),因为如果同班有两个并列第一,mm=1就只返回一个结果。使用RANK()

查询每个班的第一名的成绩:

复制代码
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;

RANK()在处理相同值时序号一样,但是会占位,排名可能是:12225

DENSE_RANK()在处理相同值时序号一样,但是不会占位,数字连续出现:12223

NTILE()

NTILE函数是用来将数据切割成指定数量的桶(buckets),并将每个数据行分配到对应的桶中。它可用于将数据划分为相等的小切片,为每一行分配该小切片的数字序号。

NTILE不支持ROWS BETWEEN,比如NTILE(2) OVER(PARTITION BY dept_no ORDER BY salary ROWS BETWEEN 3 PRECEDING - AND CURRENT ROW)。

搬运一些例子便于理解:

sql 复制代码
SELECT name, dept_no, salary,
       ntile(2) over(order by salary) n1,
       -- 全局按照salary升序排列,数据切成2份
       ntile(2) over(partition by dept_no order by salary) n2, 
       -- 按照dept_no分组,在分组内按照salary升序排列,数据切成2份
       ntile(3) over(partition by dept_no order by salary) n3 
       -- 按照dept_no分组,在分组内按照salary升序排列,数据切成3份
FROM data;

对于第三个例子:

NTILE(3) OVER(PARTITION BY dept_no ORDER BY salary)是根据dept_no列进行分组,意味着每个部门的数据会独立进行切割成3份。数据在每个分组内根据salary排序,然后再将排序后的数据切割成3份,并且每份数据的大小相对均匀。


参考自:窗口函数之ntile()函数讲解https://blog.csdn.net/godlovedaniel/article/details/116571187

总结&区别

select ROW_NUMBER()over(order by name) as 排序,* from temp

--- 排序,即使值一样,也不会重复排序。例如1,2,3,4,5

select RANK()over(order by name) as 排序,* from temp

--- 排序,值一样,就重复排序,有间隙。例如1,1,3,4

select DENSE_RANK()over(order by name) as 排序,* from temp

--- 排序,值一样,就重复排序,没有间隙。例如1,1,2,2,3,4,5

select NTILE(2)over(order by name) as 排序,* from temp

--- 排序,分成2组。此函数一般用于取表中前百分之几的数据。例如,取数据的前25%就将数据分4组,然后字段的条件是等于1。

--这里引用博客:[窗口函数over](https://blog.csdn.net/qq_55342245/article/details/122300899)的例子

相关推荐
学地理的小胖砸4 小时前
【Python 操作 MySQL 数据库】
数据库·python·mysql
数据库幼崽4 小时前
MySQL 8.0 OCP 1Z0-908 121-130题
数据库·mysql·ocp
betazhou5 小时前
基于Linux环境实现Oracle goldengate远程抽取MySQL同步数据到MySQL
linux·数据库·mysql·oracle·ogg
喝醉的小喵7 小时前
【mysql】并发 Insert 的死锁问题 第二弹
数据库·后端·mysql·死锁
付出不多7 小时前
Linux——mysql主从复制与读写分离
数据库·mysql
钊兵7 小时前
hivesql是什么数据库?
大数据·hive
源远流长jerry8 小时前
MySQL的缓存策略
数据库·mysql·缓存
初次见面我叫泰隆8 小时前
MySQL——3、数据类型
数据库·mysql
weixin_4723394610 小时前
MySQL MCP 使用案例
数据库·mysql
fengye20716112 小时前
在MYSQL中导入cookbook.sql文件
数据库·mysql·adb