窗口函数-分组排序: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)的例子

相关推荐
麦聪聊数据2 小时前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
myzshare3 小时前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序
辞砚技术录4 小时前
MySQL面试题——索引2nd
数据库·mysql·面试
墨笔之风5 小时前
java后端根据双数据源进行不同的接口查询
java·开发语言·mysql·postgres
黑白极客5 小时前
怎么给字符串字段加索引?日志系统 一条更新语句是怎么执行的
java·数据库·sql·mysql·引擎
哈里谢顿6 小时前
小探mysql覆盖索引
mysql
X***07886 小时前
理解 MySQL 的索引设计逻辑:从数据结构到实际查询性能的系统分析
数据库·mysql·sqlite
warton887 小时前
ubuntu24 安装 proxsql 实现数据库代理
linux·运维·mysql·ubuntu
天意pt7 小时前
Blog-SSR 系统操作手册(v1.0.0)
前端·vue.js·redis·mysql·docker·node.js·express
麦麦大数据8 小时前
J009 美食推荐可视化大数据系统vue+springboot
vue.js·spring boot·mysql·推荐算法·美食·可视化分析·沙箱支付