目录

目标

窗口函数概念和语法

概念

概念一

概念二

概念三

语法一

语法二

常用的窗口函数

ROW_NUMBER()

DENSE_RANK()

RANK()

NTH_VALUE()

FIRST_VALUE()

LAST_VALUE()

NTILE()

LAG()

LEAD()


目标

  • 理解窗口函数的概念和语法(本文以MySQL8.0版本为例);
  • 掌握常见的窗口函数的使用场景,并能做出相关优化,这里主要讲解非聚合函数的用法。

窗口函数概念和语法

概念

概念一

窗口操作不会将查询行组折叠为单个输出行。相反,它们为每一行生成一个结果。以查询每个学生总成绩为演示案例:

建立学生成绩表

CREATE TABLE `course_score` (`id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',`courseId` INT DEFAULT NULL COMMENT '课程主键',`studentId` INT DEFAULT NULL COMMENT '学生主键',`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',`score` FLOAT(4,1) DEFAULT NULL COMMENT '分数',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生成绩表'

插入相关数据

INSERT INTO `course_score` (`id`, `courseId`, `studentId`, `create_time`, `score`)
VALUES (1, 100001, 200001, '2021-06-10 11:22:41', 99.5),(2, 100002, 200001, '2021-06-04 11:23:02', 115.5),(3, 100003, 200001, '2021-06-10 11:23:23', 150.0),(4, 100001, 200002, '2021-06-01 11:23:41', 85.0),(5, 100002, 200002, '2021-06-10 11:23:51', 140.0),(6, 100003, 200002, '2021-06-10 11:24:01', 130.0),(7, 100001, 200003, '2021-06-10 11:24:19', 120.0),(8, 100002, 200003, '2021-06-11 11:24:37', 120.0),(9, 100003, 200003, '2021-06-05 11:24:44', 150.0);

查询每个学生总成绩

SELECT courseId, studentId, SUM(score) OVER (PARTITION BY studentId ) AS score_group
FROM `course_score`
ORDER BY studentId

结果集


概念二

OVER子句可以为空,如果为空,则表示将所有查询行作为一个分区,以查询所有学生成绩总和为演示案例:

查询所有学生成绩总和

SELECT courseId, studentId, SUM(score) OVER () AS score_group
FROM `course_score`
ORDER BY courseId

结果集


概念三

OVER子句计算之前,先执行WHERE和HAVING(如果有),以条件查询部分学生部分课程的成绩总和为演示案例:

条件查询部分学生部分课程的成绩总和

SELECT DISTINCT courseId, studentId, SUM(score) OVER () AS score_group
FROM `course_score`
WHERE courseId IN (100001, 100002)
HAVING studentId IN (200001, 200002)
ORDER BY courseId

结果集


语法一

OVER(窗口规则)

  1. 窗口规则可以为空,参考上述概念二部分;
  2. 窗口规则有几个可选项,包含:[窗口名称][分区子句][顺序子句][框架子句]

窗口规则

  1. 窗口名称:由WINDOW查询中其他地方的子句定义的窗口的名称。
  2. 分区子句:PARTITION BY子句如何将查询行分组。给定行的窗口函数结果基于包含该行的分区的行。
  3. 顺序子句:MySQL 扩展是允许表达式和列名。
  4. 框架子句:即ORDER BY排序。默认为ASC未指定方向。NULL升序排序首先排序,降序排序最后排序。

以天为分区,查询成绩总和

/*第一种*/
SELECT courseId, studentId, create_time ,
SUM(score) OVER (PARTITION BY LEFT(create_time, 10) ) AS score_group
FROM `course_score`
/*第二种*/
SELECT courseId, studentId, create_time ,
SUM(score) OVER (w) AS score_group
FROM `course_score`
WINDOW w AS (PARTITION BY LEFT(create_time, 10))

 以课程排序,计算成绩总和

SELECT courseId, studentId, create_time ,
SUM(score) OVER (ORDER BY courseId) AS score_group
FROM `course_score`


语法二

OVER 窗口名称

  1. 实际上是用WINDOW关键词定义窗口规则,方便利用别名调用窗口规则。

以天为分区,查询成绩总和

SELECT courseId, studentId, create_time ,
SUM(score) OVER w AS score_group
FROM `course_score`
WINDOW w AS (PARTITION BY LEFT(create_time, 10)) 


常用的窗口函数

ROW_NUMBER()

建立表

CREATE TABLE `train_course_rate` (`rateId` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',`courseId` BIGINT NOT NULL COMMENT '课程ID',`value` TINYINT NOT NULL DEFAULT '0' COMMENT '评分(0-100)',`employeeId` BIGINT NOT NULL COMMENT '评分人',PRIMARY KEY (`rateId`),KEY `idx_train_course_rate_courseId` (`courseId`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb3 COMMENT='课程评分'

插入相关数据

INSERT INTO train_course_rate (courseId, employeeId, rateId, VALUE)
VALUES (10001, 20001, NULL, 100),(10001, 20002, NULL, 100),(10001, 20003, NULL, 98),(10001, 20004, NULL, 90),(10002, 20001, NULL, 100),(10002, 20002, NULL, 98),(10002, 20003, NULL, 90),(10002, 20004, NULL, 90),(10003, 20001, NULL, 100),(10003, 20002, NULL, 98),(10003, 20003, NULL, 90),(10003, 20004, NULL, 92),(10004, 20001, NULL, 100),(10004, 20002, NULL, 100),(10004, 20003, NULL, 90),(10004, 20004, NULL, 90),(10005, 20001, NULL, 100),(10005, 20002, NULL, 100),(10005, 20003, NULL, 90),(10005, 20004, NULL, 90),(10006, 20001, NULL, 100),(10006, 20002, NULL, 99),(10006, 20003, NULL, 96),(10006, 20004, NULL, 95);

需求:分数相同不并列,格式如:1-2-3。

SELECT *
FROM (SELECT rateId, courseId, ROW_NUMBER() OVER (PARTITION BY courseId ORDER BY `value` DESC) AS score_order, `value`FROM train_course_rate
) t
WHERE score_order <= 3

结果集


DENSE_RANK()

需求:分数相同并列,格式如:1-1-1-2-2-3-3;

SELECT *
FROM (SELECT rateId, courseId, DENSE_RANK() OVER (PARTITION BY courseId ORDER BY `value` DESC) AS score_order, `value`FROM train_course_rate
) t
WHERE score_order <= 3

结果集


RANK()

需求:分数相同并列,且排名延后,格式如:1-1-1-4-5。

SELECT *
FROM (SELECT rateId, courseId, RANK() OVER (PARTITION BY courseId ORDER BY `value` DESC) AS score_order, `value`FROM train_course_rate
) t
WHERE score_order <= 3

结果集


NTH_VALUE()

需求:在窗口内查询每个学生分数为第1和第2的数据。

SELECT studentId, courseId, `score`, NTH_VALUE(`score`, 1) OVER w AS one_score, NTH_VALUE(`score`, 2) OVER w AS two_score
FROM `course_score`
WINDOW w AS (PARTITION BY studentId ORDER BY `score` DESC)

结果集


FIRST_VALUE()

需求:在窗口内查询每个学生分数为第1的数据。

SELECT studentId, courseId, `score`, FIRST_VALUE(`score`) OVER w AS first_score
FROM `course_score`
WINDOW w AS (PARTITION BY studentId ORDER BY `score` DESC)

结果集


LAST_VALUE()

需求:在窗口内查询每个学生分数为最低分数的数据。

SELECT studentId, courseId, `score`, LAST_VALUE(`score`) OVER w AS last_score
FROM `course_score`
WINDOW w AS (PARTITION BY studentId ORDER BY `score` DESC)

结果集


NTILE()

需求:按照课程ID,将评分按照从大到小排名到出前三名。

SELECT courseId, `value`, NTILE(3) OVER w AS `level`
FROM train_course_rate
WINDOW w AS (PARTITION BY courseId ORDER BY `value` DESC)

结果集


LAG()

需求:查询窗口内上一个分数。

SELECT courseId, `value`, LAG(`value`) OVER w AS `lag_value`
FROM train_course_rate
WINDOW w AS (PARTITION BY courseId ORDER BY `value` DESC)

结果集


LEAD()

需求:查询窗口内下一个分数。

SELECT courseId, `value`, LEAD(`value`) OVER w AS `lead_value`
FROM train_course_rate
WINDOW w AS (PARTITION BY courseId ORDER BY `value` DESC)

结果集


官方文档

窗口函数概念和语法

MySQL窗口函数大纵深作战理论指导相关推荐

  1. MySQL窗口函数简介

    原文地址:https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_last-value 译 ...

  2. mysql truncate 大表_MySQL删除大表时潜在的问题(drop table,truncate table)

    case1,删除大表时,因为清理自适应hash索引占用的内容导致的MySQL服务挂起 case2,大表的随意Drop或者truncate导致MySQL服务的挂起 按照本文中的结论就是 MySQL5.6 ...

  3. [Mysql]过大sql文件导入过慢问题解决

    [Mysql]过大sql文件导入过慢问题解决 参考文章: (1)[Mysql]过大sql文件导入过慢问题解决 (2)https://www.cnblogs.com/ttkl/p/12023640.ht ...

  4. 【实施工程师】MySQL导入大sql 文件大小限制问题的解决

    [实施工程师]MySQL导入大sql 文件大小限制问题的解决 解决过程如下: 1.由于mysql能解析sql的压缩文件,因此将200M压缩后为5M. 2.默认情况下:MySQL导入文件大小有限制的,最 ...

  5. mysql 字符大对象_第02期:MySQL 数据类型的艺术 - 大对象字段

    我以前分享过一篇<MySQL 大对象一例>,今天就来详细说下大对象的优缺点以及使用场景. 我们把 MySQL 的大对象类型分 TEXT/BLOB 和 JSON 两部分来说明. 一.TEXT ...

  6. mysql入门优化_MySQL数据库:MySQL十大优化技巧详解

    本文主要向大家介绍了MySQL数据库的MySQL十大优化技巧详解,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. WEB开发者不光要解决程序的效率问题,对数据库的快速访问和相应也是 ...

  7. MySQL 开启大页内存

    1. 开启大页内存 概述: 有些硬件或操作系统支持大于默认值的内存页(通常为4KB),这个时取决于底层硬件和操作系统.执行大页内存可以检查设备缓冲区的丢失.也可以改进性能. MySQL 使用Innod ...

  8. mysql迁移后数据对比_Oracle/云MySQL/MsSQL“大迁移”真相及最优方案

    原标题:Oracle/云MySQL/MsSQL"大迁移"真相及最优方案 最近一段时间碰到一些数据迁移的项目,如:Oracle迁移到MySQL,MsSQL迁移到MySQL,云MySQ ...

  9. MySql下大数据量级别(1000万+)优化查询和操作方法

    MySql下大数据量级别(1000万+)优化查询和操作方法 一.[原则一]: insert into tb (...) values(...),(...)...; 要比 insert into tb ...

最新文章

  1. 【Java集合源码剖析】Java集合框架
  2. 《UNIX环境编程》第十六章--网络IPC:套接字
  3. html lt table 设置数据,vue_+_element_ui_动态添加table数据
  4. java读取mysql配置文件_Linux运维:MySQL读写分离解决方案
  5. 【面试题】HashMap 面试 21 问
  6. Tomcat6.0配置集合
  7. 通过mysqladmin监控MySQL数据的服务器状态
  8. 可穿戴设备的发展与挑战
  9. 计算机网络自顶向下第七版第二章课后答案,《计算机网络·自顶向下方法》第七版 第二章 课后习题与问题 答案...
  10. Windows易升升级指南(解决大版本间更新95%的问题)
  11. 软件测试 | 期末复习——软件质量概述
  12. 状态机FSM的输出如何避免毛刺?
  13. (10.1.3.2)浅谈扁平化设计—– keep it simple
  14. 制作3D游戏时如何避免或减轻玩家的晕3D现象?
  15. WORD中表格的跨页显示
  16. Android JNI函数大全
  17. python刷新腾讯云cdn
  18. Unity InputField输入框调用win10平板虚拟键盘
  19. PHP:安装fileinfo扩展
  20. 网站下拉菜单,选择下拉后自动填充(图)

热门文章

  1. signature=690f0caf8c5a9d46ba4b18c0443239bb,Coated glass fibers
  2. 月入一万,活在北京 (zz)
  3. make[1]: *** [stage1-bubble] Error 2
  4. 【Unity】Textmesh pro制作Font Asset
  5. 武汉工程大学计算机学院吴云韬,鲁统伟-武汉工程大学计算机科学与工程学院...
  6. torch gather函数理解 图解
  7. Similar Strings
  8. cf1204E(div2)E
  9. 7zip压缩及排除目录或文件
  10. 2022-2028全球与中国内存测试设备市场现状及未来发展趋势