MySQL 窗口函数

server/2025/1/21 11:26:17/
MySQL 窗口函数
  • 1,窗口函数
    • 1.1,什么是窗口函数
    • 1.2,基本语法
  • 2,函数详解
    • 2.1,聚合函数
    • 2.2,排序函数
    • 2.3,偏移函数
    • 2.4,值函数
  • 3,进阶用法

1,窗口函数

1.1,什么是窗口函数

MySQL窗口函数是一种强大的工具,用于在查询中执行复杂的统计分析,而不需要改变表的结构或数据。MySQL从8.0版本开始支持窗口函数,这些函数也被称为分析函数,因为它们能够处理相对复杂的报表统计分析场景。

窗口的意思是将数据进行分组,每个分组即是一个窗口,这和使用聚合函数时的group by分组类似,但与聚合函数不同的地方是: 聚合函数(例如:sum/avg/min/max)会针对每个分组(窗口)聚合出一个结果(每一组返回一个结果)。 窗口函数会对每一条数据进行计算,并不会使返回的数据变少(每一行返回一个结果)

1.2,基本语法

-- 匿名窗口
SELECT <窗口函数> over (partition by <分组列名> order by <排序列名>)
FROM `表名` -- 显式窗口
SELECT <窗口函数> OVER w
FROM `表名` 
WINDOW w AS (partition by <分组列名> order by <排序列名>)

<窗口函数>的位置,可以放以下两种函数:

  1. 聚合函数:如SUM、AVG、COUNT、MAX、MIN等,可以在不合并行的情况下计算每行的聚合值。
  2. 专用窗口函数:
    • 排序函数:包括RANK、DENSE_RANK、ROW_NUMBER等,用于为数据集中的每行分配一个唯一的排名或编号。
    • 偏移函数:包括LAG和LEAD等,用于获取当前行之前的或之后的指定偏移量的值
    • 值函数:FIRST_VALUE和LAST_VALUE返回窗口分区中第一行或最后一行的值,而NTH_VALUE则返回窗口内偏移指定offset后的值。

因为窗口函数是对where或者group by子句处理后的结果进行操作,所以窗口函数一般出现在select子句或者order by子句中。
where, group by, having都不可引用该列,因为这些语句执行在select之前,此时函数尚未计算出值。

2,函数详解

原始数据如下,表名:class
在这里插入图片描述

2.1,聚合函数

窗口操作不会将多组查询行折叠成单个输出行。相反,它们为每一行产生一个结果:

SELECT *,-- 总计SUM(score) OVER () AS sum1,  -- 按course分组求和SUM(score) OVER (PARTITION BY course) AS sum2, -- 按course分组累计求和SUM(score) OVER (PARTITION BY course ORDER BY score DESC) AS sum3	
FROM `class` 

在这里插入图片描述

SELECT *,SUM(score) OVER w AS sum,AVG(score) OVER w AS avg,MIN(score) OVER w AS min,MAX(score) OVER w AS max,COUNT(score) OVER w AS count
FROM `class` 
WINDOW w AS (PARTITION BY course ORDER BY score DESC)

在这里插入图片描述

注意分数相同时,分组累计(标黄处)的处理逻辑(见:《3,进阶用法》)

2.2,排序函数

SELECT *,ROW_NUMBER() OVER w AS 'row_number',RANK() OVER w AS 'rank',DENSE_RANK() OVER w AS 'dense_rank'
FROM `class` 
WINDOW w AS (PARTITION BY course ORDER BY score DESC)

在这里插入图片描述

三者的区别如下:
row_number() 排序相同时不会重复,会根据顺序排序,即:1、2、3、4;
rank() 排序相同时会重复,序号有空隙,即1、2、2、4这样的排序结果;
dense_rank() 排序相同时会重复,序号无空隙,即1、2、2、3这样的排序结果;

求每门课程的前两名:

SELECT * FROM (SELECT *,RANK() OVER (PARTITION BY course ORDER BY score DESC) AS `rank`FROM `class` ) f 
WHERE `rank` <= 2// 窗口函数得到的列别名不能用于where, group by, having等子句,
// 因为这些语句执行在select之前,此时函数尚未计算出值。
// 以下写法是错误的:
SELECT *,RANK() OVER (PARTITION BY course ORDER BY score DESC) AS `rank`
FROM `class` 
WHERE `rank` <= 2

在这里插入图片描述

如果每门课程只需要前两条数据,可把RANK() 函数换成 ROW_NUMBER()

2.3,偏移函数

语法:LEAD(字段, 偏移量, 填充值)
偏移量默认为1,填充值默认为NULL

SELECT *,-- 获取前面一行的scoreLAG(score) OVER W AS `lag`,-- 获取后面第二行score,且无数据填充0LEAD(score, 2, 0) OVER W AS `lead`
FROM `class` 
WINDOW w AS (PARTITION BY course ORDER BY score DESC)

在这里插入图片描述

2.4,值函数

SELECT *,-- 获取第一行的scoreFIRST_VALUE(score) OVER w AS `first`,-- 截止到当前行,获取最后一行scoreLAST_VALUE(score) OVER w AS `last`,-- 截止到当前行,获取最后2行scoreNTH_VALUE(score, 2) OVER w AS `second`,-- 截止到当前行,获取最后3行scoreNTH_VALUE(score, 3) OVER w AS `third`
FROM `class`
WINDOW w AS (PARTITION BY course ORDER BY score DESC)

在这里插入图片描述
注意了:从结果看,我们对FIRST_VALUE()很清晰,就是获取的第一个值,但是LAST_VALUE()和NTH_VALUE获取的值跟我们想象中的不太一样呢? 没错,LAST_VALUE()和NTH_VALUE是获取的截止到当前为止的值,而不是整个组的最后一个值后指定的值(见:《3,进阶用法》)。

3,进阶用法

<窗口函数> over (partition by <用于分组的列名>order by <用于排序的列名>rows/range 窗口子句)

rows/range:窗口子句,主要用来限制分组(也称窗口)的行数和数据范围。

窗口子句必须和order by 子句同时使用,如果指定了order by 子句未指定窗口子句,则默认为RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即从当前分组起点到当前行。

行比较分析函数lead和lag无窗口子句。

窗口子句常用语法:

  • CURRENT ROW:当前行
  • UNBOUNDED:无界限(起点或终点)
  • PRECEDING:往前
  • FOLLOWING:往后

如上文《2.4,值函数》,如果想获取整个窗口的LAST_VALUE()和NTH_VALUE:

SELECT *,-- 获取第一行的scoreFIRST_VALUE(score) OVER w AS `first`,-- 获取最后一行scoreLAST_VALUE(score) OVER w AS `last`,-- 获取最后2行scoreNTH_VALUE(score, 2) OVER w AS `second`,-- 获取最后3行scoreNTH_VALUE(score, 3) OVER w AS `third`
FROM `class`
WINDOW w AS (PARTITION BY course ORDER BY score DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

在这里插入图片描述
rows 和range区别:

  1. rows是物理窗口,即根据order by 子句排序后,取的前N行及后N行的数据计算(与当前行的值无关,只与排序后的行号相关)。
  2. range是逻辑窗口,即根据order by 子句排序后,取的前N行及和当前行有相同order by值的所有行数据计算。

例如在《2.1,聚合函数》飘黄部分,因为默认窗口字句是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,所以改成把"RANGE"改成"ROWS"就是逐条统计:

SELECT *,-- 默认RANGESUM(score) OVER w AS sum1,-- 指定ROWSSUM(score) OVER (w ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS sum2,-- 默认RANGECOUNT(score) OVER w AS count1,-- 指定ROWSCOUNT(score) OVER (w ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS count2
FROM `class` 
WINDOW w AS (PARTITION BY course ORDER BY score DESC)

在这里插入图片描述


http://www.ppmy.cn/server/160158.html

相关文章

Qt中登录界面布局设计(详细图文教程)

&#x1f4aa; 图像算法工程师&#xff0c;专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &a…

SDL2基本的绘制流程与步骤

SDL2(Simple DirectMedia Layer 2)是一个跨平台的多媒体库,它为游戏开发和图形应用提供了一个简单的接口,允许程序直接访问音频、键盘、鼠标、硬件加速的渲染等功能。在 SDL2 中,屏幕绘制的流程通常涉及到窗口的创建、渲染目标的设置、图像的绘制、事件的处理等几个步骤。…

Mybatis 进阶 / Mybatis—Puls (详细)

目录 一.动态SQL 1.1标签 1.2 标签 1.3标签 1.4标签 1.5标签 1.6标签 mybatis总结&#xff1a; 二.Mybatis-Puls 2.1准备工作 2.2CRUD单元测试 2.2.1创建UserInfo实体类 2.2.2编写Mapper接⼝类 2.2.3 测试类 2.3 常见注解 2.3.1TableName 2.3.2TableField 2.4打印日…

计算机网络 (47)应用进程跨越网络的通信

前言 计算机网络应用进程跨越网络的通信是一个复杂而关键的过程&#xff0c;它涉及多个层面和组件的协同工作。 一、通信概述 计算机网络中的通信&#xff0c;本质上是不同主机中的应用进程之间的数据交换。为了实现这种通信&#xff0c;需要借助网络协议栈中的各层协议&#x…

算法(蓝桥杯)贪心算法7——过河的最短时间问题解析

一、题目描述 在漆黑的夜里&#xff0c;N位旅行者来到了一座狭窄且没有护栏的桥边。他们只带了一只手电筒&#xff0c;且桥窄得只够让两个人同时过。如果各自单独过桥&#xff0c;N人所需的时间已知&#xff1b;若两人同时过桥&#xff0c;则所需时间是走得较慢的那个人单独行动…

w-form-select 组件中 分析 自定义属性 和 el-select 自带属性 的对比表格

以下是该组件中 自定义属性 和 el-select 自带属性 的对比表格&#xff1a; 属性/功能自定义el-select 自带说明label✔️❌自定义属性&#xff0c;用于设置表单项的标签。prop✔️❌自定义属性&#xff0c;用于表单验证时的字段名。labelWidth✔️❌自定义属性&#xff0c;用…

Taro+Vue实现图片裁剪组件

cropper-image-taro-vue3 组件库 介绍 cropper-image-taro-vue3 是一个基于 Vue 3 和 Taro 开发的裁剪工具组件&#xff0c;支持图片裁剪、裁剪框拖动、缩放和输出裁剪后的图片。该组件适用于 Vue 3 和 Taro 环境&#xff0c;可以在网页、小程序等平台中使用。 源码 https:…

IDEA导入Maven工程不识别pom.xml

0 现象 把阿里 sentinel 项目下载本地后&#xff0c;IDEA 中却没显示 maven 工具栏。 1 右键Maven Projects 点击IDEA右侧边栏的Maven Projects&#xff0c;再点击&#xff1a; 在出现的选择框中选择指定的未被识别的pom.xml即可&#xff1a; 2 Add as maven project 右键p…