【数据库高级】Mysql窗口函数的使用和练习

news2024/11/25 2:19:43

Mysql窗口函数

  • 🌾Mysql窗口函数
  • 🕊️一、什么是窗口函数
    • 🍃1、怎么理解窗口?
    • 🍃2、什么是窗口函数
      • 🍵1. 基本语法:
      • 🍵2. 窗口函数多用在什么场景?主要有以下两类:
      • 🍵3. 我们常见的窗口函数和聚合函数有这些:
      • 🍵4. 窗口函数和普通聚合函数的区别?
  • 🕊️二、窗口函数的练习
    • 🍃1、序号函数
    • 🍃2、分布函数:
    • 🍃3、前后函数
    • 🍃4、首尾函数
    • 🍃5、其他函数
  • 🕊️三、实战

🌾Mysql窗口函数

本文主要介绍了MySQL窗口函数的定义和具体使用。

首先窗口函数是从MySQL8.0开始支持的,如果现在使用的是MySQL5.0或者8.0一下的版本,那么非常遗憾,建议搞个8.0版本试一试,哈哈~

🕊️一、什么是窗口函数

🍃1、怎么理解窗口?

搞清楚窗口代表着啥,才知道什么时候该用它。

窗口函数是相对于聚函数来说的。

  • 聚合函数是对一组数据计算后返回单个值(即分组)。
  • 非聚合函数一次只会处理一行数据。
  • 而窗口函数在行记录上计算某个字段的结果时,可将窗口范围内的数据输入到聚合函数中,并不改变行数。

在这里插入图片描述

在这里插入图片描述

根据上面所说,准备如下员工表信息数据

-- 员工表
create table if not exists sql_niukewang.`employee`
(
    `eid` int not null auto_increment comment '员工id' primary key,
    `ename` varchar(20) not null comment '员工名称',
    `dname` varchar(50) not null comment '部门名称',
    `hiredate` date not null comment '入职日期',
    `salary` double null comment '薪资'
) comment '员工表';
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('傅嘉熙', '开发部', '2022-08-20 12:00:04', 9000);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('武晟睿', '开发部', '2022-06-12 13:54:12', 9500);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('孙弘文', '开发部', '2022-10-16 08:27:06', 9400);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('潘乐驹', '开发部', '2022-04-22 03:56:11', 9500);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('潘昊焱', '人事部', '2022-02-24 03:40:02', 5000);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('沈涛', '人事部', '2022-12-14 09:16:37', 6000);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('江峻熙', '人事部', '2022-05-12 01:17:48', 5000);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('陆远航', '人事部', '2022-04-14 03:35:57', 5500);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('姜煜祺', '销售部', '2022-03-23 03:21:05', 6000);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('邹明', '销售部', '2022-11-23 23:10:06', 6800);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('董擎苍', '销售部', '2022-02-12 07:54:32', 6500);
insert into sql_niukewang.`employee` (`ename`, `dname`, `hiredate`, `salary`) values ('钟俊驰', '销售部', '2022-04-10 12:17:06', 6000);

在这里插入图片描述

我们举个例子:分别使用聚合函数sum()和窗口函数sum()来根据部门求和看下两者区别

select
dname,sum(salary) sum 
from employee group by dname;

在这里插入图片描述

select
dname,salary,
sum(salary) over(partition by dname order by salary) sum
from employee;

在这里插入图片描述

​ 通过观察,正如之前所说,窗口函数相对聚合函数,聚合函数是将一组数据计算后返回单个值,而窗口函数在行记录上计算某个字段的结果时,可将窗口范围内的数据输入到聚合函数中,并不改变行数,就好比如我们刚刚根据部门开窗求和salary薪资,每一行的sum数据是将前面范围内的数据都聚合到当前结果中。

​ 所以可见,窗口就是范围的意思,可以理解为一些记录(行)的集合;窗口函数也就是在满足某种条件的记录集合上执行计算的特殊函数。

在这里插入图片描述

🍃2、什么是窗口函数

窗口函数也叫OLAP函数(Online Anallytical Processing),可以对数据进行实时分析处理。

🍵1. 基本语法:

<窗口函数> OVER (PARTITION BY <用于分组的列名> ORDER BY <用于排序的列名>);
-- over关键字用于指定函数的窗口范围,
-- partition by 用于对表分组,
-- order by子句用于对分组后的结果进行排序。

注意:窗口函数是对where或者group by子句处理后的结果再进行二次操作,因此会按照SQL语句的运行顺序,窗口函数一般放在select子句中(from前),例如上一条SQL,可以往上拖着看看~

🍵2. 窗口函数多用在什么场景?主要有以下两类:

  • 排名问题,例如:查包子铺利润月排名;
  • TOPN问题,例如:查每种包子利润最高的两个月;

🍵3. 我们常见的窗口函数和聚合函数有这些:

  • 专用窗口函数:rank()dense_rank()row_number()
  • 聚合函数:max()min()count()sum()avg()

窗口函数都有哪些?

在这里插入图片描述

在这里插入图片描述

  • 序号函数:row_number() / rank() / dense_rank()
  • 分布函数:percent_rank() / cume_dist()
  • 前后函数:lag() / lead()
  • 头尾函数:first_val() / last_val()
  • 其他函数:nth_value() / nfile()

🍵4. 窗口函数和普通聚合函数的区别?

因为聚合函数也可以放在窗口函数中使用,因此窗口函数和普通聚合函数也很容易被混淆,二者区别如下:

  • 聚合函数是将多条记录聚合为一条;而窗口函数是每条记录都会执行,有几条记录执行完还是几条
  • 聚合函数也可以用于窗口函数中,这个我会举例说明。

🕊️二、窗口函数的练习

还是使用上面的员工表信息完成下面的练习。

🍃1、序号函数

序号函数有:ROW_NUMBER、RANK、DENSE_RANK,也就是序号排名的意思。

ROW_NUMBER():顺序排序 —— 1、2、3

RANK():并列排序,跳过重复序号 —— 1、1、3

DENSE_RANK():并列排序,不跳过重复序号 —— 1、1、2

**应用场景:**求每个部门的员工薪资排名

  1. ROW_NUMBER()函数
select 
dname,salary,
row_number() over(partition by dname order by salary) sum 
from employee;

在这里插入图片描述

  1. RANK()函数
select 
dname,salary,
rank() over(partition by dname order by salary) ranking 
from employee;

在这里插入图片描述

  1. DENSE_RANK()函数
select 
dname,salary,
dense_rank() over(partition by dname order by salary) ranking
from employee;

在这里插入图片描述

总结:

上面针对同一个应用场景使用三种不同的序号函数,得到三种不同的结果,我们重点需要注意在三种结果的区别。

  • row_number()函数只是做一个顺序排序 —— 1、2、3…
  • rank()函数做了顺序排序,但是做了并列排序,并跳过重复序号 —— 1、1、3
  • dense_rank()函数

🍃2、分布函数:

分布函数有:percent_rank() 、 cume_dist()

cume_dist()分组内小于、等于当前rank值的行数 / 分组内总行数

percent_rank()每行按照公式(rank-1) / (rows-1)进行计算

  1. CUME_DIST()函数

**应用场景:**查询小于等于当前薪资(salary)的比例

select 
dname,ename,salary,
rank() over(partition by dname order by salary) ranking,
cume_dist() over(order by salary) dist1,
cume_dist() over(partition by dname order by salary) dist2
from employee;

在这里插入图片描述

​ 这里使用了序号函数 row_number(),目的是为了更好的理解分布函数的cume_dist()函数。

cume_dist()函数作用是分组内小于、等于当前rank值的行数 / 分组内总行数,如上结果人事部的rank值为4行,

<=5000的rank值行数为2,分组内总行数为4,所以cume_dist的值=(2/4)=0.5。

​ 以此类推,下面的结果都是这样的。

注意:没有使用partition by 分组的默认是所有数据为一组,比如上面的dist1列的数据

  1. percent_rank()函数

用途:每行按照公式(rank-1) / (rows-1)进行计算。

其中,rank为RANK()函数产生的序号,rows为当前窗口的记录总行数
应用场景:不常用

select 
dname,ename,salary,
rank() over(partition by dname order by salary) ranking,
percent_rank() over(partition by dname order by salary) per
from employee;

在这里插入图片描述

/*
 per:
  第一行: (1 - 1) / (4 - 1) = 0
  第二行: (1 - 1) / (4 - 1) = 0
  第三行: (3 - 1) / (4 - 1) = 0.6666666666666666
  第四行:(4 - 1) / (4 - 1) = 1
*/

由上面的注释我们可以理解percent_rank()函数的使用,我们可以把它转换为

  • 如果是升序排列,前面比你小的还有多少
  • 如果是降序排列,前面比你大的还有多少

应用场景不是很多,但是咱们也可以学习一下,万一以后遇到了也知道之前好像接触过~

🍃3、前后函数

前后函数有:LAG、LEAD

LAG(expr,n):返回位于当前行的前n行

LEAD(expr,n):后n行的expr的值

  • 返回当前行的前n行(本组)的expr值
  • lag允许你在每一个分组内, 从当前行向前看n行数据
  • n(也叫offset)是从当前行偏移的行数,以获取值。offset必须是一个非负整数。如果offset为零,则LAG()函数计算当前行的值。如果省略 offset,则LAG()函数默认使用n=1, 向前看一个数据。
  1. LAG(expr,n)前函数

应用场景:求各部门内部相邻组员的薪资差

第一步:先使用前函数查出前一个员工薪资

select dname,ename,salary,
lag(salary,1) over(partition by dname order by salary) presalary  from employee;

在这里插入图片描述

第二步:把第一步的结果作为表进行查询,并做-运算

select * ,(salary-presalary)  from (
	select dname,ename,salary,
	lag(salary,1) over(partition by dname order by salary) presalary  from employee
) pre_table;

在这里插入图片描述

  1. LEAD(expr,n)后函数

应用场景:求各部门内部相邻组员的薪资差

其实和上面的LAG函数一样,只不过就是一个是向上偏移,一个是向下偏移。

第一步:先使用前函数查出后一个员工薪资

select dname,ename,salary,
lead(salary,1) over(partition by dname order by salary) presalary  from employee;

第二步:把第一步的结果作为表进行查询,并做-运算

select * ,(salary-presalary)  from (
	select dname,ename,salary,
	lead(salary,1) over(partition by dname order by salary) presalary  from employee
) pre_table;

在这里插入图片描述

总结:对于前后函数,向前还是向后偏移大家可以灵活使用。

🍃4、首尾函数

首尾也叫头尾函数,有first_value(expr)last_value(expr)

first_value(expr)取分组排序后,截止到当前第一个值

last_value(expr)取分组排序后,截止到当前最后一个值

需求:截止到当前,按照日期排序查询第1个入职和最后1个入职员工的薪资

first_value(expr)函数

select * ,first_value(salary) over(partition by dname order by hiredate) first from employee;

在这里插入图片描述

last_value(expr)函数和first_value(expr)函数是一样的,这里就不再模拟演示了。

🍃5、其他函数

NTH_VALUE(expr, n)、NTILE(n)

NTILE(n):将分区中的有序数据分为n个等级,记录等级数

NTH_VALUE(expr, n):返回窗口中第n个expr的值。expr可以是表达式,也可以是列名

  1. ntile(n)函数

需求:将每个部门员工按照入职日期分成2组

select * , 
ntile(2) over(partition by dname order by hiredate) `group` 
from employee;

在这里插入图片描述

  1. nth_value(expr,n)函数

需求:截止到当前薪资,显示每个员工的薪资中排名第2或者第3的薪资

select * , 
nth_value(salary,2) over(partition by dname order by hiredate) twoSalary ,
nth_value(salary,3) over(partition by dname order by hiredate) threeSalary 
from employee;

在这里插入图片描述

🕊️三、实战

  1. 牛客网:[SQL33 找出每个学校GPA最低的同学](找出每个学校GPA最低的同学_牛客题霸_牛客网 (nowcoder.com))

在这里插入图片描述
还有其他的,比如说力扣上等等,这里之举个例子,没事多可以刷刷


在这里插入图片描述

【数据库基础】数据库介绍和三大范式

【数据库基础】MySQL增删改查基础操作命令

【数据库高级】数据完整性和多表查询

【数据库】事务

【数据库高级】Mysql窗口函数的使用和练习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/53221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AAAI2023】视觉辅助的常识知识获取Visually Grounded Commonsense Knowledge Acquisition 个人学习笔记

视觉辅助的常识知识获取 摘要&#xff1a;大规模的常识知识库为广泛的AI应用提供了能力&#xff0c;其中常识知识的自动提取extraction of commonsense knowledge (CKE)是一个基本和具有挑战性的问题。文本中的CKE因其固有的稀疏性和文本中常识的报道偏差reporting bias而闻名…

Windows OpenGL ES 图像色调

目录 一.OpenGL ES 图像色调 1.原始图片2.效果演示 二.OpenGL ES 图像色调源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零基础 OpenGL E…

Java+JSP+MySQL基于SSM的在线投票系统-计算机毕业设计

项目介绍 随着社会的发展&#xff0c;人们在处理一些问题的时候不同意见越来越多&#xff0c;这源于人们对思想的解放和对社会的认识。所以在处理同一问题上&#xff0c;为了征求不同人的意见在线投票系统诞生了。 基于SSM的在线投票系统以钦州学院为背景&#xff0c;运用在校…

CSS详解

文章目录1. CSS快速入门2. 四种CSS导入方式3. 三种基本选择器4. 层次选择器5. 结构伪类选择器5. 属性选择器6. CSS样式HTML(结构)CSS(表现)JavaScript(交互)1. CSS快速入门 <style>可以编写css代码&#xff0c;每一个声明&#xff0c;最好使用分号; <!DOCTYPE html&…

【JavaWeb】Servlet系列 --- HttpServletRequest接口详解(接口方法要记住!!!)

HttpServletRequest接口一、HttpServletRequest接口中有哪些常用的方法&#xff1f;思考&#xff1a;如果是前端的form表单提交了数据之后&#xff0c;你准备怎么存储这些数据&#xff0c;你准备采用什么样的数据结构去存储这些数据呢&#xff1f;二、request接口中四个非常重要…

FlutterAcivity 包已导入 但是仍然爆红

FlutterAcivity 包已导入 但是仍然爆红 这种情况就比较广泛了 我说一下我遇到的这种情况 上一篇 FlutterActivity找不到http://t.csdn.cn/HvgtI 1.大家可以看到我这个FlutterActivity包已导入 但是依然报错 2.可以清楚的看到我这个提示是 LifecycleOwner 找不到我们点Flutter…

智慧工地安全施工实时监测系统解决方案

背景介绍 随着经济的发展&#xff0c;混凝土搅拌车数量有很大增长&#xff0c;但是其超速、超载等原因造成了很多交通事故&#xff0c;给交通安全带来隐患&#xff0c;也给企业造成损失&#xff0c;严重影响了和谐城市建设的进程。 中国电子科技集团第52研究所经过多年研发与…

React子组件没有随父组件更新问题的解决

前言&#xff1a;今天遇到一个小需求&#xff0c;本来只是修改文案的&#xff0c;结果问题卡了很久很久&#xff0c;想想还是太菜了 问题描述&#xff1a; 根据changePlaceHolder修改AInput的placeholder的默认值&#xff0c;AInput是封装的antd的input组件&#xff0c;期间发…

图片一键调整工具V1.0-免费版

一、工具介绍 这是博主自己开发的图片一键调整工具V1.0,它可以调整图片宽度和高度、压缩图片大小、改变图片背景、转换图片格式和图片透明化&#xff0c;都是很常用的功能。操作起来简单方便。 二、工具操作 1.调整图片背景 首先&#xff0c;把该工具软件和图片放到同一文件…

Linux基础知识与实操-篇二:初识Linux目录管理与操作

文章目录文件与目录管理相对路径与绝对路径目录相关操作查阅文件相关操作文件预设权限搜索与文件文件的搜索基本权限与指令最后在经过上篇 篇一:初识Linux文件权限与配置 后&#xff0c;我们已经基本熟悉并使用了Linux关于文件管理相关的内容&#xff0c;本篇则继续从文件深入…

CrossOver2023虚拟机软件安装双系统教程

您喜欢切换Windows系统吗&#xff1f;喜欢&#xff1f;好吧&#xff0c;您随意。对于其他人而言&#xff0c;想要不依赖于笨重的 Windows 模拟器就能在您的 Mac 系统上运行微软的应用程序&#xff0c;CrossOver是最简单的方式。讲真&#xff0c;您试过模拟器了吗&#xff1f;您…

如何使用Python访问和查询Google BigQuery数据

要使用Python查询Google BigQuery数据&#xff0c;需要将Python客户端连接到BigQuery实例。 将会云客户端库用于Google BigQuery API. 假设您已经设置了Python开发环境。(支持3.7-3.11版本)要安装该库&#xff0c;请在命令行中运行以下命令&#xff1a; pip install --upgrade…

【国际化Intl】Flutter 国际化多语言实践

目标&#xff1a;实现flutter国际化 提示&#xff1a;这里参考一下几个链接 例如&#xff1a; https://github.com/ThinkerWing/language https://juejin.cn/post/6844903823119482888 这篇也很详细&#xff0c;还有包括兼容中文的繁体简体… 可以看看 feat/use-Flutter-Int…

python函数进阶

一、函数多返回值 Q&#xff1a;如果一个函数内两个return&#xff0c;程序如何执行&#xff1f; A&#xff1a;只执行了第一个return&#xff0c;原因是因为return可以退出当前函数&#xff0c;导致return下方的代码不执行 但是如果一个函数需要有多个返回值&#xff0c;该如…

华为云数据库GaussDB(for Cassandra)揭秘:高性能低成本是什么样的体验?

在我们的日常理念中&#xff0c;追求性价比是最为常见的&#xff0c;但是你知道购买低配置还能享受高性能、低延时、超低价的数据库有哪些吗&#xff1f;今天我们就用数据说话&#xff0c;带你深入了解GaussDB(for Cassandra)挑战高性价比&#xff01; 众所周知&#xff0c;有…

Android开发者们想想:到底是市场饱和?还是你们技术饱和?

根据我的不客观数据体验来看&#xff0c;最饱和的是iOS&#xff0c;同样发布一个职位iOS是其他技术岗位10倍的投递量。当然Android作为一个已经市场化将近十几年的技术门类&#xff0c;它必然早已经是成熟常态。这样的技术行业都不再会有爆炸式的增长。连同Android硬件、手机、…

Go学习之路:方法和接口(DAY 3)

文章目录前引方法和接口1.1、方法/声明方法1.2、方法/捆绑其他类型1.3、方法/方法常用指针传递1.4、方法/普通函数指针传递和方法指针传递区别2.1、接口/方法签名集合2.2、接口/接口断言2.3、接口/switch case练习题、接口/stringer实现字符串打印2.4、接口/错误前引 昨天终于算…

机器学习5数据归一化Feature Scaling

文章目录一、为什么要数据归一化&#xff1f;二、解决方案数据归一化&#xff0c;解决方案1&#xff1a;最值归一化normalization&#xff1a;解决方案2&#xff1a;均值方差归一化standardization;三、最值归一化处理normalization四、均值方差归一化Standardization一、为什么…

ICMP协议(3层网络层协议:IP、ARP、ICMP)

1、ICMP协议端口号&#xff1f; 没有端口号&#xff0c;向TCP/UDP这些都是没有端口号只有协议号&#xff0c;只有应用层才有端口号。 2、ICMP协议是干什么的&#xff1f; 网络探测与回馈机制 1&#xff09;网络探测 2&#xff09;路由跟踪&#xff0c;windows命令&#xff1a;…

ABP:内置logger and 第三方库serilog 之间的关系

今天在看项目的日志记录功能&#xff0c;比较疑惑为什么项目中有的地方使用 Logger< T > _logger 然后又在资源文件下看见日志的第三方库 Serilog 解答&#xff1a; ASP.NET Core Build-in Logging ASP.NET Core 提供了 Logging 的抽象接口, third party 都会依据抽象来…