MySQL 窗口函数是什么,有这么好用

先看这段像天书一样的 SQL ,看着就头疼。

SELECTs1.name,s1.subject,s1.score,sub.avg_score AS average_score_per_subject,(SELECT COUNT(DISTINCT s2.score) + 1 FROM scores s2 WHERE s2.score > s1.score) AS score_rank
FROM scores s1
JOIN (SELECT subject, AVG(score) AS avg_scoreFROM scoresGROUP BY subject
) sub ON s1.subject = sub.subject
ORDER BY s1.score DESC;

这段SQL是干什么用的呢,就是为了计算一个成绩排名,简直大动干戈啊。

那有没有简化的方法呢?有的。

简化后的版本就是利用今天说的窗口函数。

SELECTname,subject,score,AVG(score) OVER (PARTITION BY subject) AS average_score_per_subject,RANK() OVER (ORDER BY score DESC) AS score_rank
FROM scores
ORDER BY score DESC;

是不是看上去就简洁清晰多了。

下面我们看看是什么样的功能。

首先创建一个表,包含姓名、学科、分数三个字段,用于后面功能的演示。

CREATE TABLE `scores` (`name` varchar(20) COLLATE utf8_bin NOT NULL,`subject` varchar(20) COLLATE utf8_bin NOT NULL,`score` int(3) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

然后向表中插入一些随机记录。

INSERT INTO scores (name, subject, score) VALUES ('Student1', '化学', 75);
INSERT INTO scores (name, subject, score) VALUES ('Student2', '生物', 92);
INSERT INTO scores (name, subject, score) VALUES ('Student3', '物理', 87);
INSERT INTO scores (name, subject, score) VALUES ('Student4', '数学', 68);
INSERT INTO scores (name, subject, score) VALUES ('Student5', '英语', 91);
INSERT INTO scores (name, subject, score) VALUES ('Student6', '化学', 58);
INSERT INTO scores (name, subject, score) VALUES ('Student7', '物理', 79);
INSERT INTO scores (name, subject, score) VALUES ('Student8', '数学', 90);
INSERT INTO scores (name, subject, score) VALUES ('Student9', '数学', 45);

##什么是窗口函数

在 MySQL 8.x 版本中,MySQL 提供了窗口函数,窗口函数是一种在查询结果的特定窗口范围内进行计算的函数。

很早以前用 Oracle 和 MS SQL 的时候会用到里面的窗口函数,但是用 MySQL 后才发现,MySQL 竟然没有窗口函数,以至于一些负责的统计查询都要用各种子查询、join,层层嵌套,看上去很简单的需求,结果搞得 SQL 语句写的是龙飞凤舞,别人一看跟天书似的。就一个字儿,懵。

窗口函数主要的应用场景是统计和计算,例如对查询结果进行分组、排序和计算聚合,通过各个函数的组合,可以实现各种复杂的逻辑,而且比起 MySQL 8.0之前用子查询、join 的方式,性能上要好得多。

OVER()

OVER() 是用于定义窗口函数的子句,它必须结合其他的函数才有意义,比如求和、求平均数。而它只用于指定要计算的数据范围和排序方式。

function_name(...) OVER ([PARTITION BY expr_list] [ORDER BY expr_list] [range]
)

PARTITION BY

用于指定分区字段,对不同分区进行分析计算,分区其实就列,可以指定一个列,也可以指定多个列。

ORDER BY

用于对分区内记录进行排序,排序后可以与「范围和滚动窗口」一起使用。

范围和滚动窗口

用于指定分析函数的窗口,包括范围和滚动窗口。

范围窗口(Range window)

指定窗口的起止行号,使用UNBOUNDED PRECEDING表示起点,UNBOUNDED FOLLOWING表示终点。

例如:

SUM(salary) OVER (ORDER BY id  RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING)

这会计算当前行及之前5行和之后5行的salary总和。

滚动窗口(Row window)

使用了基于当前行的滚动窗口

例如:

SUM(salary) OVER (ORDER BY id  ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING)

这会计算当前行及之前2行和之后2行的salary总和。

OVER()可搭配的函数:

聚合函数

MAX(),MIN(),COUNT(),SUM()等,用于生成每个分区的聚合结果。

排序相关

ROW_NUMBER(),RANK(),DENSE_RANK()等,用于生成每个分区的行号或排名。

窗口函数

LAG(),LEAD(),FIRST_VALUE(),LAST_VALUE()等,用于基于窗口框生成结果。

搭配聚合函数

1、按subject列进行分区,并求出某学科的最大最小值

获取分数和此学科最高分

SELECT subject,score, MAX(score) OVER (PARTITION  BY subject) as `此学科最高分` FROM scores;

得出的结果是:

subjectscore此学科最高分
化学7575
化学5875
数学6890
数学9090
数学4590
物理8787
物理7987
生物9292
英语9191

2、获取学科的报名人数

SELECT subject,score, count(name) OVER (PARTITION  BY subject) as `报名此学科人数` FROM scores;

得到的结果为:

subjectscore报名此学科人数
化学752
化学582
数学683
数学903
数学453
物理872
物理792
生物921
英语911

3、求学科的总分

SELECT subject, SUM(score) OVER (PARTITION  BY subject) as `此学科总分` FROM scores;

得到的结果:

subject此学科总分
化学133
化学133
数学203
数学203
数学203
物理166
物理166
生物92
英语91

4、使用 order by 求累加分数

SELECT name,subject,score, SUM(score) OVER (order  BY score) as `累加分数` FROM scores;

得到的结果:

namesubjectscore累加分数
Student9数学4545
Student6化学58103
Student4数学68171

我们看这是怎么算出来的,OVER 函数里面是 order by 。

首先根据分数排序(默认升序),得到第一行分数是45,所以累加分数就是它自己,也就是45。

然后排序得到第二行 58,然后将第一行和第二行相加,这样得到累加分数就是45+58=103。

同理,第三行就是前三行的总和,也就是45+58+68=171。

以此类推,第 N 行就是1~N的累加和。

5、使用 order by + 范围

前面因为没有限定范围,所以就是前 N 行的累加,还可以限定范围。

SELECT name,subject,score, SUM(score) OVER (order BY `score` ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as `累加分数` FROM scores;

这里的累加分数是指当前行+前一行+后一行的和。

获取的结果为:

namesubjectscore累加分数
Student9数学45103
Student6化学58171
Student4数学68201
Student1化学75222
Student7物理79241
Student3物理87256
Student8数学90268
Student5英语91273

第一行 103,是当前行 45+后一行(58)的和,等于103,因为没有前一行。

第二行171,是当前行58+前一行(45)+后一行(68)的和,等于171。

以此类型,后面的累加分数都是这样算出来的。

搭配排序相关函数

ROW_NUMBER()

ROW_NUMBER() 函数用于为结果集中的每一行分配一个唯一的排序。

如下,对成绩进行排名,分数高的排在前面,如果有两个人分数相同,那仍然是一个第一,另一个第二。

SELECT name,subject,score, ROW_NUMBER() OVER (order BY `score` desc) as `排名` FROM scores;

查询结果为:

namesubjectscore排名
Student2生物921
Student5英语912
Student8数学903
Student3物理874
Student7物理795

如果不用 ROW_NUMBER(),比如在 MySQL 5.7的版本中,就会像下面这样:

SELECT s1.name, s1.subject, s1.score, COUNT(s2.score) + 1 AS `排名`
FROM scores s1
LEFT JOIN scores s2 ON s1.score < s2.score
GROUP BY s1.name, s1.subject, s1.score
ORDER BY s1.score DESC;

是不是比使用 ROW_NUMBER()复杂的多。

RANK()

RANK() 函数用于为结果集中的每一行分配一个排名值,它也是排名的,但是它和 ROW_NUMBER()有,RANK()函数在遇到相同值的行会将排名设置为相同的,就像是并列排名。

就像是奥运比赛,如果有两个人都是相同的高分,那可能就是并列金牌,但是这时候就没有银牌了,仅次于这两个人的排名就会变成铜牌。

SELECT name,subject,score, RANK() OVER (order BY `score` desc) as `排名` FROM scores;

查询结果为:

namesubjectscore排名
Student1化学921
Student2生物921
Student5英语913
Student8数学904
Student3物理875

DENSE_RANK()

DENSE_RANK() 也是用作排名的,和 RANK()函数的差别就是遇到相同值的时候,不会跳过排名,比如两个人是并列金牌,排名都是1,那仅次于这两个人的排名就是2,而不像 RANK()那样是3。

SELECT name,subject,score, DENSE_RANK() OVER (order BY `score` desc) as `排名` FROM scores;

查询结果为:

namesubjectscore排名
Student1化学921
Student2生物921
Student5英语912
Student8数学903

配合其他窗口函数

NTILE()

NTILE() 函数用于将结果集划分为指定数量的组,并为每个组分配一个编号。例如,将分数倒序排序并分成4个组,相当于有了4个梯队。

SELECT name,subject,score, NTILE(4) OVER (order BY `score` desc) as `` FROM scores;

查询结果为:

namesubjectscore
Student1化学921
Student2生物921
Student5英语911
Student8数学902
Student3物理872
Student7物理793
Student4数学683
Student6化学584
Student9数学454

LAG()

LAG() 函数用于在查询结果中访问当前行之前的行的数据。它允许您检索前一行的值,并将其与当前行的值进行比较或计算差异。LAG()函数对于处理时间序列数据或比较相邻行的值非常有用。

LAG()函数完整的表达式为 LAG(column, offset, default_value),包含三个参数:

column:就是列名,获取哪个列的值就是哪个列名,很好理解。

offset: 就是向前的偏移量,取当前行的前一行就是1,前前两行就是2。

default_value:是可选值,如果向前偏移的行不存在,就取这个默认值。

例如比较相邻两个排名的分数差,可以这样写:

SELECTname,subject,score,ABS(score - LAG(score, 1,score) OVER (ORDER BY score DESC)) AS `分值差`
FROMscores;

得到的结果为:

namesubjectscore分值差
Student1化学920
Student2生物920
Student5英语911
Student8数学901
Student3物理873
Student7物理798
Student4数学6811

LEAD()

LEAD() 函数和 LAG()的功能一致,只不过它的偏移量是向后偏移,也就是取当前行的后 N 行。

所以前面的比较相邻两行差值的逻辑,也可以向后比较。

SELECTname,subject,score,score - LEAD(score, 1,score) OVER (ORDER BY score DESC) AS `分值差`
FROMscores;

得到的结果:

namesubjectscore分值差
Student1化学920
Student2生物921
Student5英语911
Student8数学903
Student3物理878
Student7物理7911
Student4数学6810

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

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

相关文章

Android 13 MTK平台添加自定义按键,以及CTS问题解决

添加自定义按键流程 一般来说上层添加以下几处修改 驱动层的键值上报,让驱动处理好即可 frameworks / base/core/java/android/view/KeyEvent.java public static final int KEYCODE_DEMO_APP_4 = 304;/** add by songhui for fingerprint Key code */+ public static fina…

IntelliJ IDEA Bookmark使用

1 增加 右键行号栏 2 查看 从favorite这里查看 参考IntelliJ IDEA 小技巧&#xff1a;Bookmark(书签)的使用_bookmark idea 使用_大唐冠军侯的博客-CSDN博客

neo4j的CQL命令实例演示

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

07-2_Qt 5.9 C++开发指南_二进制文件读写(stm和dat格式)

文章目录 1. 实例功能概述2. Qt预定义编码文件的读写2.1 保存为stm文件2.2 stm文件格式2.3 读取stm文件 3. 标准编码文件的读写3.1 保存为dat文件3.2 dat文件格式3.3 读取dat文件 4. 框架及源码4.1 可视化UI设计4.2 mainwindow.cpp 1. 实例功能概述 除了文本文件之外&#xff…

pve和openwrt以及我的电脑中网络的关系和互通组网

情况1 一台主机 有4个口&#xff0c;分别eth0,eth1,eth2,eth3 pve有管理口 这个情况下 &#xff0c;没有openwrt 直接电脑和pve管理口连在一起就能进pve管理界面 情况2 假设pve 的管理口味eth0 openwrt中桥接的是eth0 eth1 eth2 那么电脑连接eth3或者pve管理口设置eth3&#xf…

【C#】设置有线网卡IP地址,子网掩码,网关,DNS

方法 public partial class ComputerInfo{/// <summary>/// 设置IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;DNS/// </summary>public static List<NetworkAdapterInfo> SetIpAddressSubMaskDnsGeteway(string ipAddress, string subMask, stri…

MySQL库的操作

文章目录 MySQL库的操作1. 创建数据库2. 字符集和校验规则(1) 查看系统默认字符集以及校验规则(2) 查看数据库支持的字符集和校验规则(3) 案例(4) 校验规则对数据库的影响 3. 查看数据库4. 修改数据库5. 删除数据库6. 数据库的备份和恢复(1) 备份(2) 还原 7. 查看连接情况 MySQ…

在 Windows 中恢复数据的 5 种方法

发生数据丢失的原因有多种。无论是因为文件被意外删除、文件系统或操作系统损坏&#xff0c;还是由于软件或硬件级别的存储故障&#xff0c;数据都会在您最意想不到的时候丢失。今天我们重点介绍五种数据恢复方法&#xff0c;以应对意外情况的发生。 1.从另一台机器启动硬盘 如…

分享一组天气组件

先看效果&#xff1a; CSS部分代码&#xff08;查看更多&#xff09;&#xff1a; <style>:root {--bg-color: #E9F5FA;--day-text-color: #4DB0D3;/* 多云 */--cloudy-background: #4DB0D3;--cloudy-temperature: #E6DF95;--cloudy-content: #D3EBF4;/* 晴 */--sunny-b…

python基础环境建设(pip、anaconda)

1.pip 配置文件路径&#xff1a; centos&#xff1a;~/.pip/pip.conf windows: C:\Users\admin\AppData\Roaming\pip\pip.ini 文件内容&#xff1a; [global] index-url http://IP/repository/pypi-tsinghua/simple trusted-hostIP今天centos7.9、python3.6环境 pip install…

Https、CA证书、数字签名

Https Http协议 Http协议是目前应用比较多应用层协议&#xff0c;浏览器对于Http协议已经实现。Http协议基本的构成部分有 请求行 &#xff1a; 请求报文的第一行请求头 &#xff1a; 从第二行开始为请求头内容的开始部分。每一个请求头都是由K-V键值对组成。请求体&#xf…

【C++入门到精通】C++入门 —— vector (STL)

阅读导航 前言一、vector简介1. 概念2. 特点 二、vector的使用1.vector 构造函数2. vector 空间增长问题⭕resize 和 reserve 函数 3. vector 增删查改⭕operator[] 函数 三、迭代器失效温馨提示 前言 前面我们讲了C语言的基础知识&#xff0c;也了解了一些数据结构&#xff0…

软件测试基础篇——Docker

1、docker技术概述 docker描述&#xff1a;docker是一项虚拟化的容器技术&#xff08;类似于虚拟机&#xff09;&#xff0c;docker技术给使用者提供一个平台&#xff0c;在该平台上可以利用提供的容器&#xff0c;对每一个应用程序进行单独的封装隔离&#xff0c;每一个应用程…

spring 2.7.14 cors 设置 allowedOrigins(“*“)通配符 失效怎么解决

失效代码&#xff1a; package com.yukuanyan.searcher_web.config;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebM…

计算机竞赛 opencv python 深度学习垃圾图像分类系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; opencv python 深度学习垃圾分类系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 这是一个较为新颖的竞…

图像的伽马变换

伽马变换&#xff08;Gamma Correction&#xff09;是一种在图像处理中常用的非线性变换方法&#xff0c;用于调整图像的亮度和对比度。它在图像的像素值上应用一个幂次函数&#xff0c;以改变图像的灰度级分布&#xff0c;从而影响图像的感知亮度。伽马变换通常用于纠正显示器…

Monkey测试真的靠谱吗?

Monkey测试&#xff0c;顾名思义&#xff0c;就是模拟一只猴子在键盘上乱敲&#xff0c;从而达到测试被测系统的稳定性。Monkey测试&#xff0c;是Android自动化测试的一种手段&#xff0c;Monkey测试本身非常简单&#xff0c;Android SDK 工具支持adb Shell命令&#xff0c;实…

208、仿真-51单片机脉搏心率与心电报警Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…

ElasticSearch 7.4学习记录(基础概念和基础操作)

若你之前从未了解过ES&#xff0c;本文将由浅入深的一步步带你理解ES&#xff0c;简单使用ES。作者本人就是此状态&#xff0c;通过学习和梳理&#xff0c;产出本文&#xff0c;已对ES有个全面的了解和想法&#xff0c;不仅将知识点梳理&#xff0c;也涉及到自己的理解&#xf…

行业追踪,2023-08-09

自动复盘 2023-08-09 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…