学习MySQL(五):窗口函数

窗口函数介绍

窗口函数的引入是为了解决想要既显示聚集前的数据,又要显示聚集后的数据;窗口数对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。

强调:使用MySQL 8.0版本方可实现

基本语法

函数名(列) over(选项) 选项为partition by 列 order by 列

解释:

  • over(partition by xxx) 按xxx分组的所有行进行分组
  • over(partition by xxx order by aaa) 按列xxx分组,按列aaa排序
  • over(order by aaa) 按aaa列排序
  • over括号中的partition by和order by的使用根据具体情况选择
-- 需求:计算每个学生的及格科目数
-- 使用聚合函数,类似数据透视表,原有表结构已发生变化
SELECT student_id,count( sid ) FROM score WHERE    num >= 60 GROUP BY student_id;-- 使用窗口函数,不会更改原表结构
SELECT student_id,count( sid ) over ( PARTITION BY student_id ORDER BY student_id ) AS 及格数
FROM score WHERE num >= 60;

聚合窗口函数

语法:聚合函数(列) over(partition by 列 order by 列)

常见的聚合函数:sum() count() avg() max() min()

排序窗口函数

  • row_number():仅仅根据行号进行排序,相同结果则排序按照顺序依次排
  • rank():排名,与row_number函数不同的是,rank函数考虑到了over子句中排序字段值相同的情况,over子句中排序字段值相同的排序结果是一样的,后面字段值不相同的序号将跳过相同的排名号排下一个。如:11335
  • dense_rank():密集排序,用法跟rank类似,唯一不同是当排序结果相同时,排序不跳跃,而是紧跟排下一个。如:11223
  • ntile():桶排序,首先,ntile会先根据你的分组依据,然后把每个组的总记录数进行按照你给的ntile(n)里的数字n进行均分,这个数字就是桶数,例如一个组内总共12条记录,若n=6,则等划分成6桶,然后按照num的排序等级划分,12/6=2则每个桶两条记录,也就是112233445566的排序结果,常用于提取前百分之多少的应用场景。

都是排名函数,不同之处在对于名次相同的数据处理方式

-- 对每门课程进行排序
SELECTs.sid,s1.sname,s1.gender,c.cname,s.num,row_number() over ( PARTITION BY c.cname ORDER BY num DESC ) AS row_number排名,rank() over ( PARTITION BY c.cname ORDER BY num DESC ) AS rank排名,dense_rank() over ( PARTITION BY c.cname ORDER BY num DESC ) AS dense_rank排名,ntile( 6 ) over ( PARTITION BY c.cname ORDER BY num DESC ) AS ntile排名 
FROMscore AS sJOIN student AS s1 ON s.student_id = s1.sidLEFT JOIN course AS c ON s.course_id = c.cid-- 计算每门课程前三,考虑排名相同的情况
SELECT * FROM (SELECT s.sid,s1.sname,s1.gender,c.cname,s.num,dense_rank() over ( PARTITION BY c.cname ORDER BY num DESC ) AS dense_rank排名 FROMscore AS sJOIN student AS s1 ON s.student_id = s1.sidLEFT JOIN course AS c ON s.course_id = c.cid ) AS a 
WHEREdense_rank排名 <=3

位置移动窗口函数

  • lag(col,n):col列名,n行数,用于统计窗口内往上第n行值
  • lead(col,n):col列名,n行数,用于统计窗口内往下第n行值

这两个函数可以用于同列中相邻行的数据计算

应用场景:

  • 计算作弊次数
-- 需求:对于下面的数据,对于同一用户(uid)如果在2分钟之内重新登陆,则判断为作弊,统计哪些用户有作弊行为,并计算作弊次数
-- 数据代码
CREATE TABLE lead_table (id INT PRIMARY KEY,uid INT NOT NULL,login_time datetime NOT NULL );
INSERT INTO lead_table
VALUES( 1, 1, "2020-8-26 12:59:00" ),( 2, 1, "2020-8-26 13:02:23" ),( 3, 1, "2020-8-26 13:03:34" ),( 4, 1, "2020-8-26 13:09:00" ),( 5, 2, "2020-8-26 13:57:00" ),( 6, 2, "2020-8-26 13:59:00" ),( 7, 2, "2020-8-26 13:59:45" );

思路:根据题目要求,如果能把相邻两列的下面一列与上面那一列变成同一行,不久能实现相减了么,因此我们可以多生成一列,例如:把uid都为1的第二行记录生成到第一行,以此类推,这就可以用到lead往下移动的操作了

-- 第一步
SELECT id,uid,login_time,
LEAD( login_time, 1 ) OVER ( PARTITION BY uid ORDER BY login_time ) lead_time
FROM lead_table;--第二步
SELECT id,uid,login_time,
LEAD( login_time, 1 ) OVER ( PARTITION BY uid ORDER BY login_time ) lead_time,
TIMESTAMPDIFF(SECOND,login_time,LEAD( login_time, 1 ) OVER ( PARTITION BY uid ORDER BY login_time )) AS 相差秒数 
FROM lead_table;-- 最终代码
SELECT uid,COUNT( 1 ) AS 作弊次数
FROM(SELECT id,uid,login_time,LEAD( login_time, 1 ) OVER ( PARTITION BY uid ORDER BY login_time ) lead_time,TIMESTAMPDIFF(SECOND,login_time,lead( login_time, 1 ) OVER ( PARTITION BY uid ORDER BY login_time )) AS 相差秒数 
FROM lead_table ) AS e 
WHERE 相差秒数 <= 120 
GROUP BY uid;
  • 计算次日留存率

其他窗口函数

  • first_value(column):取分组排序后第一个值
SELECT s.sid,s1.sname,s1.gender,c.cname,s.num,
FIRST_VALUE(num) OVER(PARTITION by c.cname ORDER BY num DESC) AS first_value用法
FROM score AS s
JOIN student AS s1 ON s.student_id = s1.sid
LEFT JOIN course AS c ON s.course_id = c.cid
  • last_value(column):取分组排序后最后一个值
SELECT s.sid,s1.sname,s1.gender,c.cname,s.num,
LAST_VALUE(num) OVER(PARTITION by c.cname ORDER BY num DESC) AS last_value用法
FROM score AS s
JOIN student AS s1 ON s.student_id = s1.sid
LEFT JOIN course AS c ON s.course_id = c.cid

为什么和想要的结果不一样呢?

实际上,窗口函数默认统计范围是rows between unbounded preceding and current row,也就是取当前行数据与当前行之前的数据的比较。

修改SQL,在order by条件的后面加上语句:rows between unbounded preceding and unbounded following,可以理解为:当前分组数据中的所有数据进行比较,取最后一条记录。

SELECT s.sid,s1.sname,s1.gender,c.cname,s.num,
LAST_VALUE(num) OVER(PARTITION by c.cname ORDER BY num DESC rows between unbounded preceding and unbounded following) AS last_value用法
FROM score AS s
JOIN student AS s1 ON s.student_id = s1.sid
LEFT JOIN course AS c ON s.course_id = c.cid

详细介绍:

  • rows between XXX and XXX
  • unbounded 无限制的
  • preceding 分区的当前记录的向前偏移量
  • current 当前
  • following 分区的当前记录的向后偏移量

示例:累计计算每个月的销售额

-- 示例数据
CREATE TABLE sale (id INT PRIMARY KEY auto_increment,年份 INT,月份 INT,
money FLOAT ( 10, 2 ));
INSERT INTO sale ( 年份, 月份, money )
VALUES( 2020, 1, 5840 ),( 2020, 2, 5780 ),( 2020, 3, 4300 ),( 2020, 4, 4760 ),( 2020, 5, 3630 ),( 2020, 6, 4130 ),( 2020, 7, 4350 );-- 语句
SELECT *,sum( money ) over ( ORDER BY 月份rows between unbounded preceding and current row) AS 累计销售额 
FROM sale;

本章示例数据

CREATE DATABASE school;
USE school;
CREATE TABLE class (cid INT ( 11 ) NOT NULL auto_increment,caption VARCHAR ( 32 ) NOT NULL,PRIMARY KEY ( cid ) 
) ENGINE = INNODB charset = utf8;INSERT INTO class
VALUES( 1, '三年二班' ),( 2, '三年三班' ),( 3, '二年二班' ),( 4, '一年二班' ),( 5, '二年五班' );CREATE TABLE teacher (tid INT ( 11 ) NOT NULL auto_increment,tname VARCHAR ( 32 ) NOT NULL,PRIMARY KEY ( tid )
) ENGINE = INNODB DEFAULT charset = utf8;INSERT INTO teacher
VALUES( 1, '张磊老师' ),( 2, '李平老师' ),( 3, '刘兰老师' ),( 4, '朱朱老师' ),( 5, '李杰老师' );CREATE TABLE course (cid INT ( 11 ) NOT NULL auto_increment,cname VARCHAR ( 32 ) NOT NULL,teacher_id INT ( 11 ) NOT NULL,PRIMARY KEY ( cid ),KEY fk_couurse_teacher ( teacher_id ),CONSTRAINT fk_course_teacher FOREIGN KEY ( teacher_id ) REFERENCES teacher ( tid ) 
) ENGINE = INNODB DEFAULT charset = utf8;
INSERT INTO course
VALUES( 1, '生物', 1 ),( 2, '物理', 2 ),( 3, '体育', 3 ),( 4, '美术', 2 );CREATE TABLE student (sid INT ( 11 ) NOT NULL auto_increment,gender CHAR ( 1 ) NOT NULL,class_id INT ( 11 ) NOT NULL,sname VARCHAR ( 32 ) NOT NULL,PRIMARY KEY ( sid ),KEY fk_class ( class_id ),CONSTRAINT fk_class FOREIGN KEY ( class_id ) REFERENCES class ( cid ) 
) ENGINE = INNODB DEFAULT charset = utf8;INSERT INTO student
VALUES( 1, '男', 1, '理解' ),( 2, '女', 1, '钢蛋' ),( 3, '男', 1, '张三' ),( 4, '男', 1, '张思' ),( 5, '女', 1, '网易' ),( 6, '男', 1, '王二' ),( 7, '男', 2, '铁道' ),( 8, '男', 2, '李武' ),( 9, '男', 2, '刘三' ),( 10, '女', 2, '刘一' ),( 11, '男', 2, '刘思' ),( 12, '男', 3, '王三' ),( 13, '男', 3, '小五' ),( 14, '男', 3, '小七' ),( 15, '女', 3, '如花' ),( 16, '男', 3, '张四' );CREATE TABLE score (sid INT ( 11 ) NOT NULL auto_increment,student_id INT ( 11 ) NOT NULL,course_id INT ( 11 ) NOT NULL,num INT ( 11 ) NOT NULL,PRIMARY KEY ( sid ),KEY fk_score_student ( student_id ),KEY fk_score_course ( course_id ),CONSTRAINT fk_score_course FOREIGN KEY ( course_id ) REFERENCES course ( cid ),CONSTRAINT fk_score_student FOREIGN KEY ( student_id ) REFERENCES student ( sid ) 
) ENGINE = INNODB DEFAULT charset = utf8;INSERT INTO score
VALUES( 1, 1, 1, 10 ),( 2, 1, 2, 9 ),( 5, 1, 4, 66 ),( 6, 2, 1, 8 ),( 8, 2, 3, 68 ),( 9, 2, 4, 99 ),( 10, 3, 1, 77 ),( 11, 3, 2, 66 ),( 12, 3, 3, 87 ),( 13, 3, 4, 99 ),( 14, 4, 1, 79 ),( 15, 4, 2, 11 ),( 16, 4, 3, 67 ),( 17, 4, 4, 100 ),( 18, 5, 1, 79 ),( 19, 5, 2, 11 ),( 20, 5, 3, 67 ),( 21, 5, 4, 100 );

来自: 学习MySQL(五):窗口函数

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

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

相关文章

​学者观察 | 从区块链应用创新看长安链发展——CCF区块链专委会荣誉主任斯雪明

导语 2024年1月27日&#xff0c;斯雪明教授在长安链发布三周年庆暨生态年会上发表演讲&#xff0c;认为在区块链发展过程中&#xff0c;不仅需要技术创新&#xff0c;同时需要有价值、有特色、有示范意义的应用创新。斯雪明教授介绍了国内区块链技术与应用发展的现状、趋势与挑…

【数据结构】排序(直接插入排序,希尔排序)

目录 一、排序的概念 二、常见的排序算法 三、插入排序 1.直接插入排序 1.直接插入排序实现 2.直接插入排序特性及复杂度 2.希尔排序 1.排序思路 2.希尔排序实现 3.希尔排序的特性及复杂度 一、排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#x…

python手写数字识别(PaddlePaddle框架、MNIST数据集)

python手写数字识别&#xff08;PaddlePaddle框架、MNIST数据集&#xff09; import paddle import paddle.nn.functional as F from paddle.vision.transforms import Compose, Normalizetransform Compose([Normalize(mean[127.5],std[127.5],data_formatCHW)]) # 使用tran…

[Java基础揉碎]多线程基础

多线程基础 什么是程序, 进程 什么是线程 什么是单线程,多线程 并发, 并行的概念 单核cpu来回切换, 造成貌似同时执行多个任务, 就是并发; 在我们的电脑中可能同时存在并发和并行; 怎么查看自己电脑的cpu有几核 1.资源监视器查看 2.此电脑图标右键管理- 设备管理器- 处理器…

k8s 二进制安装 详细安装步骤

目录 一 实验环境 二 操作系统初始化配置&#xff08;所有机器&#xff09; 1&#xff0c;关闭防火墙 2&#xff0c;关闭selinux 3&#xff0c;关闭swap 4, 根据规划设置主机名 5, 做域名映射 6&#xff0c;调整内核参数 7&#xff0c; 时间同步 三 部署 dock…

uniapp vu3 scroll-view 滚动到指定位置

设置 scroll-view <scroll-view :scroll-y"true" :scroll-with-animation"true" :scroll-top"scrollTop" :style"height:${height}px"><view v-for"item in 10" :id"box${item}">box {{item}}</v…

原生IP介绍

原生IP&#xff0c;顾名思义&#xff0c;即初始真实IP地址&#xff0c;是指从互联网服务提供商获得的IP地址&#xff0c;IP地址在互联网与用户之间直接建立联系&#xff0c;不需要经过代理服务器代理转发。 原生IP具备以下特点。 1.直接性 原生IP可以直接连接互联网&#xff…

337_C++_内存对齐操作,内存分配、或其他需要数据对齐的场合中是很常见的操作

size_t ImagesCache::_alignSize(size_t srcSz, size_t alnSz) {if (0 == alnSz) {printf("[ImagesCache] Incorrect input parameters\n");return srcSz;

代码随想录算法训练营第五十四天

第二题我看了很久还是没太明白&#xff0c;我发现理解动规有一点点吃力了啊&#xff0c;努努力。 392.判断子序列 总感觉在不等于的时候&#xff0c;应该是dp[i][j] dp[i-1][j-2]; 这里其实按他那个图会更好理解一点。 class Solution { public:bool isSubsequence(string s, …

Gone框架介绍19 -如何进行单元测试?

gone是可以高效开发Web服务的Golang依赖注入框架 github地址&#xff1a;https://github.com/gone-io/gone 文档地址&#xff1a;https://goner.fun/zh/ 请帮忙在github上点个 ⭐️吧&#xff0c;这对我很重要 &#xff1b;万分感谢&#xff01;&#xff01; 文章目录 单元测试…

CentOs安装

安装 开发工具 &#xff1a;GCC、 JDK、mysql 如果出现蓝屏&#xff0c;要在BIOS开启虚拟化支持&#xff0c;或者移除打印机。

Google:站长移除无效网址

当您的网址不需要呈现在Google站长中时&#xff0c;您可以在站长工具中移除网址 操作步骤&#xff1a;登录Google站长&#xff0c;绑定网站完成后&#xff0c;点击左侧删除 >> 输入网址 如果遇到一些网址&#xff0c;可以找寻网址间的规律&#xff0c;比如说&#xff0…

2024生日快乐祝福HTML源码

源码介绍 2024生日快乐祝福HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c; 源码截图 源码下载 2024生日快乐祝福HTML源码

Shell脚本 <<EOF ... EOF语法(Here Document)(特殊的输入重定向方式)(定界符)

文章目录 Here Document语法Here Document 的基本语法使用场景 关于定界符定界符不是变量定界符在 Here Document 中只是一个字符串&#xff0c;主要功能是标记输入文本的开始和结束&#xff0c;使用时应遵循最佳实践格式要求例子和说明如何使用定界符定界符可重复使用&#xf…

Spring数据访问全攻略:从JdbcTemplate到声明式事务

上文讲到 —— 航向数据之海&#xff1a;Spring的JPA与Hibernate秘籍 本文目录 四. JdbcTemplate的使用定义JdbcTemplate及其在Spring中的作用展示如何使用JdbcTemplate简化数据库操作1. 配置JdbcTemplate2. 使用JdbcTemplate查询数据3. 打印查询结果 五. Spring的事务管理介绍…

桥接模式

桥接模式&#xff1a;在这种模式下&#xff0c;虚拟机就像是局域网中一台独立的主机&#xff0c;能够访问网内任何一台机器。在桥接模式下&#xff0c;必须为虚拟系统手动配置IP地址、子网掩码&#xff0c;并且这些配置需要与宿主机器处于同一网段&#xff0c;以便虚拟系统和宿…

leetcode-42. 接雨水(双指针,前缀)

42. 接雨水 /*** param {number[]} height* return {number}*/ var trap function (height) {let len height.length;let pre_max new Array(len).fill(0);let suf_max new Array(len).fill(0);pre_max[0] height[0];suf_max[len - 1] height[len - 1];for (let i 1; i…

queue使用

C的queue是一种先进先出&#xff08;FIFO&#xff09;的数据结构&#xff0c;可以用来存储一系列元素。它属于STL&#xff08;Standard Template Library&#xff09;的一部分&#xff0c;以queue模板类的形式提供。 要使用queue&#xff0c;需要包含头文件&#xff0c;并使用…

Linux shell编程学习笔记49:strings命令

0 前言 在使用Linux的过程中&#xff0c;有时我们需要在obj文件或二进制文件中查找可打印的字符串&#xff0c;那么可以strings命令。 1. strings命令 的功能、格式和选项说明 我们可以使用命令 strings --help 来查看strings命令的帮助信息。 pupleEndurer bash ~ $ strin…

在k8s中搭建elasticsearch高可用集群,并对数据进行持久化存储

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《洞察之眼&#xff1a;ELK监控与可视化》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Elasticsearch简介 2、k8s简介 二、环境准备 …