MySQL开窗函数

测试环境:mysql8.0.18
官方文档:https://dev.mysql.com/doc/refman/8.0/en/window-functions.html

  • 一、窗口函数介绍
  • 二、语法结构
  • 三、自定义窗口
    • 1.rows(重点)
    • 2.range
    • 3.默认窗口
  • 四、常用窗口函数示例
    • 1.row_number & rank & dense_rank
    • 2.lead & lag
    • 3.first_value & last_value & nth_value
    • 4.ntile
    • 5.cume_dist & percent_rank(了解)

一、窗口函数介绍

开窗函数是mysql8.0中的新特性,用于实现和group by分组函数类似的分组聚合功能。区别在于:

  • 分组函数:对一个集合输出一个标量结果,改变了数据的粒度,且丢失了非分组字段及非聚合字段的信息。
  • 开窗函数:分别以每一行为当前行,与当前行相关的所有行为窗口,对同一个窗口内的数据进行聚合等类似操作,结果附加到当前行的后面,不改变原始数据粒度,不丢失原始数据信息。

二、语法结构

开窗函数|聚合函数 over([分组函数] [排序函数] [自定义窗口]) ,over是进行开窗,里面的分组函数、排序函数、自定义窗口都可以省略。

开窗函数|聚合函数:不可省略,用于对窗口范围内的所有数据行进行某种指定操作。可以是只适用于开窗函数的非聚合函数(https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html),也可以是适用于group by的聚合函数(https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html)。
分组函数partition by ...,根据指定的字段对表分组,分组字段可以有多个。省略时表示整个表为一组。
排序函数order by ...,排序字段也可以有多个,当排序字段为多个时表示先按照第一个字段排序,当第一个字段相等确定不了顺序时再按照第二个字段排序,以此类推…

三、自定义窗口

这部分可以直接查看文档https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html,个人觉得这部分算是开窗函数里最重要的了,弄明白了各种情况下窗口的大小,其他的就没啥容易混淆的点了。

mysql中的窗口类型有两种:rowsrangerows是以物理行距离为基准通过计算与当前行的物理距离计算窗口大小,range是以当前行的值为基准通过计算与当前行值的差值计算窗口大小。

窗口大小可通过between 上界 and 下界来指定,其中,窗口的上下界分别有下面几种取值:

  • unbounded preceding:包含当前行及当前行之前的所有记录。
  • n preceding:包含当前行及当前行之前的n-1行,实际窗口大小n。
  • current row:仅包含当前行。
  • unbounded following:包含当前行及当前行之后的所有记录。
  • n following:包含当前行及当前行之后的n-1行,实际窗口大小n。

当窗口下界为current row时,可以不使用between and,也就是下面几种情况可简写:
1)between unbounded preceding and current row --> unbounded preceding
2)between n preceding and current row --> n preceding
3)between current row and current row --> current row
而following的情况不支持简写,原因可以参考下怎么理解mysql开窗函数 unbounded following这种简写形式不支持 而unbounded preceding支持,觉得有些道理。

1.rows(重点)

物理范围窗口,窗口大小只与当前行的物理距离有关。下面造点测试数据:

create table test_rows_range as
select 1 as id, '2020-10-03' as trans_date, 349 as sales
union all
select 2 as id, '2020-10-01' as trans_date, 563 as sales 
union all
select 3 as id, '2020-10-02' as trans_date, 716 as sales
union all
select 4 as id, '2020-10-05' as trans_date, 628 as sales
union all
select 5 as id, '2020-10-02' as trans_date, 412 as sales
union all
select 6 as id, '2020-10-02' as trans_date, 857 as sales
union all
select 7 as id, '2020-10-08' as trans_date, 201 as sales
union all
select 8 as id, '2020-10-05' as trans_date, 191 as sales
union all
select 9 as id, '2020-10-06' as trans_date, 675 as sales
union all
select 10 as id, '2020-10-08' as trans_date, 941 as sales;

在这里插入图片描述

select *,sum(sales) over(order by trans_date rows between 1 preceding and 1 following) as sum1,		-- 当前行的前一行、后一行、及当前行共3行作为一个窗口sum(sales) over(order by trans_date rows unbounded preceding) as sum2,		-- 当前行及当前行之前的所有行为窗口sum(sales) over(order by trans_date rows current row) as sum3		-- 仅取当前行为窗口
from test_rows_range;

output:
在这里插入图片描述

2.range

逻辑范围窗口,业务中一般都会和order by连用,否则使用range窗口没啥实际意义。range类型窗口的上下界依然可以沿用rows类型窗口的上下界,规则是以当前行order by字段的值为基准,对值按照指定的上下界范围进行加减操作以确定逻辑窗口上下界的值。例如当前行的值为3,自定义窗口大小为range between 2 preceding and 1 following,那么此时逻辑窗口的临界值为[3-2, 3+1] -> [1, 4],所有order by字段值在该范围内的行都属于当前行窗口中的记录。

这里有两个小细节:
1)因为range是以行的值为基准,按照指定的上下界对值进行加减操作以确定窗口上下临界值的范围,因此range窗口的order by排序字段只能是数值型或日期时间类型这样支持逻辑意义上加减的字段类型,否则像varchar这种类型就会报下面这个错误:
> 3587 - Window '<unnamed window>' with RANGE N PRECEDING/FOLLOWING frame requires exactly one ORDER BY expression, of numeric or temporal type
2)当排序字段为数值型时,自定义窗口的格式可以直接沿用rows中列举的上下界,例如range n preceding,这时窗口的上界值为当前行的值-n。但是如果为时间日期类型时对于n preceding这样的上界就不能使用了,因为mysql不知道是在这个时间日期的基础上-n day?还是-n hour?,因此需要用range between interval 1 day preceding and interval 1 day following这种语法格式明确一下,否则会报下面异常:
> 3588 - Window '<unnamed window>' with RANGE frame has ORDER BY expression of datetime type. Only INTERVAL bound value allowed.
但是,对于unbounded preceding这样的上界,就不用interval的形式指定,很好理解,这种上界包括了所有小于当前行的值的记录,此时是- day还是- hour已经不重要了。

-- 修改trans_date字段类型为date
alter table test_rows_range modify trans_date date;select *,sum(sales) over(order by trans_date range between interval 1 day preceding and interval 1 day following) as sum1, 	-- 当前行的日期&前一天的日期&后一天的日期 的所有行作为一个窗口sum(sales) over(order by trans_date range unbounded preceding) as sum2,		-- 所有小于等于当前行日期的行作为窗口sum(sales) over(order by trans_date range current row) as sum3		-- 仅取和当前行日期相等的行作为窗口
from test_rows_range;

output:
在这里插入图片描述

3.默认窗口

如果不显式指定窗口大小,则默认窗口大小主要分为over()中有没有order by子句两种情况:

  • 没有order by子句:默认窗口为每个组内的全部行。
  • order by子句:默认窗口为range unbounded preceding
select *,sum(sales) over() as sum1, 	-- 无order by,窗口范围为全部行sum(sales) over(order by trans_date) as sum2		-- 有order by,窗口范围为当前行及之前的所有行
from test_rows_range;

output:
在这里插入图片描述

四、常用窗口函数示例

这部分可以直接查看文档https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html

1.row_number & rank & dense_rank

这三个都是排序函数,区别在于:

  • row_number():序号不重复,不间断。
  • rank():序号可重复,可间断。
  • dense_rank(),序号可重复,不间断。
select *,row_number() over(order by trans_date) as rn,rank() over(order by trans_date) as rk,	dense_rank() over(order by trans_date) as drk
from test_rows_range;

output:
在这里插入图片描述

2.lead & lag

对指定字段整体上移(lead)或者下移(lag)。

  • lead(col, n, default):上移。参数col表示移动的字段,不可缺省;参数n表示移动的距离,可缺省,缺省值默认值为1;参数default表示当出现空值时用来填充的默认值,可缺省,缺省时用null填充。
  • lag(col, n, default):下移,参数含义同上。
select *,lead(sales,1,0) over(order by trans_date) as `lead`,	-- 将sales字段值整体上移1位,空值用0填充lag(sales,1,0) over(order by trans_date) as lag1,	-- 将sales字段值整体下移1位,空值用0填充lag(sales) over(order by trans_date) as lag2	-- 将sales字段值整体下移1位,空值不处理
from test_rows_range;

output:
在这里插入图片描述

3.first_value & last_value & nth_value

下面几个函数的作用是取窗口中指定顺序的字段值。

  • first_value(col):取窗口中字段col的第一个值。
  • last_value(col):取窗口中字段col的最后一个值。
  • nth_value(col, n):取窗口中第n顺序的值。
select *,first_value(sales) over(order by trans_date) as `first`,	-- 取每个窗口第一个值last_value(sales) over(order by trans_date) as last,	-- 取每个窗口最后一个值nth_value(sales,2) over(order by trans_date) as nth		-- 取每个窗口第二个值
from test_rows_range;

output:
在这里插入图片描述

4.ntile

将数据分组。

  • ntile(n):n是指定的组数。分组逻辑是从小到后为每条数据打上一个组号的标签,尽可能使每组内的数据相对均匀,当每组内的数据不能完全一样时,多余的数据优先给组号较小的分组。
select *,ntile(4) over(order by trans_date) as ntile4	-- 数据均匀分为4组
from test_rows_range;

output:
在这里插入图片描述

5.cume_dist & percent_rank(了解)

这两个函数基本不用,了解即可,下面是两个函数的官方描述。
在这里插入图片描述
在这里插入图片描述
从文档中可以看到这两个函数都应该与order by放在一起使用,返回的结果也都和order by字段的值有关。

  • cume_dist:返回的是窗口中所有小于等于当前行order by字段的值的总行数 / 窗口所在的分组内的总行数。
  • percent_rank:返回的是窗口中所有小于当前行order by字段的值的总行数 / 窗口所在的分组内的总行数-1。
select *,cume_dist() over(order by trans_date) as `cume_dist`,percent_rank() over(order by trans_date) as `percent_rank`
from test_rows_range;

output:
在这里插入图片描述
解释一下这个输出结果,默认窗口range unbounded preceding,对于cume_dist列,第一行trans_date为’2020-10-01’时,窗口内小于等于这一行的总行数为1,而这个窗口所在的分组也就是整个表总行数为10,因此第一行结果为0.1;而对于后面3个连续的0.4,是因为窗口类型为range,小于等于第二行值’2020-10-02’的总行数为4,所以结果为0.4。

对于percent_rank列,窗口所在的分组也就是整个表总行数为10,所以分母都为10-1=9。窗口内小于第一行’2020-10-01’的总行数为0,所以该列第一个值为0,后面以此类推…

PS
文档中没看到直接的描述,但在测试中发现了这两个函数有一些特点:
1)只适用于range类型窗口,这并不是说显式指定rows会报错,而是mysql忽略指定,输出的结果和range类型一致。
2)窗口范围自定义无效,也就是只能为默认窗口range unbounded preceding,像是修改为range between interval 1 day preceding and interval 1 day preceding无效。

select *,cume_dist() over(order by trans_date) as dist_range,cume_dist() over(order by trans_date rows unbounded preceding) as dist_rows,percent_rank() over(order by trans_date) as percent_range,percent_rank() over(order by trans_date rows unbounded preceding) as percent_rows,percent_rank() over(order by trans_date range between interval 1 day preceding and interval 1 day preceding) as percent_range1	-- 自定义窗口无效,不影响输出
from test_rows_range;

output:
在这里插入图片描述
可以看到结果均无变化,我的理解是这两个函数都是用来计算某行记录在排序后的总体分布情况,因此rows类型的窗口因为忽略了重复值的影响所以不合适。而在此需求中更没必要让用户可以自定义指定窗口,因为这两个需求的总体思路都是按照当前行值在所有数据中的相对位置 / 所有记录数这样的思路来计算。

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

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

相关文章

开源推荐榜【Taichi 专为高性能计算机图形学设计的编程语言】

Taichi是一个高性能的并行编程语言&#xff0c;它被嵌入在Python中&#xff0c;使得开发者能够轻松编写可移植的、高性能的并行程序。这个库的核心优势在于它能够将计算密集型的Python代码在运行时通过即时编译器(Just-In-Time, JIT)转换成快速的机器代码&#xff0c;从而加速P…

吴恩达2022机器学习专项课程(一) 4.1 梯度下降

问题预览 梯度下降算法的作用是&#xff1f;梯度下降的过程&#xff1f;梯度下降和最小化成本函数的联系&#xff1f;所有的成本函数都是一个形状吗&#xff1f;在非凸形状中&#xff0c;梯度下降的更新过程是&#xff1f;在非凸形状中&#xff0c;不同的初值对最小化成本函数…

使用itext-core生成PDF

1、添加引用依赖包 <dependency><groupId>com.itextpdf</groupId><artifactId>itext-core</artifactId><version>8.0.3</version><type>pom</type></dependency> 2、上代码 package com.student.demo.pdf;impor…

011_string_and_cell_in_Matlab中的字符串与元胞数组

Matlab中的字符串与元胞数组 1. 字符串 1.1 为什么 这两个东西拉在一起讲&#xff0c;是因为在2016a之前的Matlab中&#xff0c;要表示一个字符串的数组&#xff0c;只能用元胞数组。 最初的字符串在Matlab中的类型是字符&#xff0c;在Matlab中&#xff0c;一个字符就是一…

Sentinel原理及实践

Sentinel 是什么 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 为什么使用sentinel&…

解决前后端通信跨域问题

因为浏览器具有同源策略的效应。 同源策略是一个重要的网络安全机制&#xff0c;用于Web浏览器中&#xff0c;以防止一个网页文档或脚本来自一个源&#xff08;域、协议和端口&#xff09;&#xff0c;获取另一个源的数据。同源策略的目的是保护用户的隐私和安全&#xff0c;防…

基于Spring Boot的在线学习系统的设计与实现

基于Spring Boot的在线学习系统的设计与实现 摘 要 在线学习系统是以大学传统线下教学方式不适应信息技术的迅速发展为背景&#xff0c;提高学习效率&#xff0c;解决传统教学问题&#xff0c;并且高效的实现教学信息化的一款软件系统。为了更好的实现对于教学和学生的管理&a…

FL Studio21.2.3中文版软件新功能介绍及下载安装步骤教程

FL Studio21.2中文版的适用人群非常广泛&#xff0c;主要包括以下几类&#xff1a; FL Studio 21 Win-安装包下载如下: https://wm.makeding.com/iclk/?zoneid55981 FL Studio 21 Mac-安装包下载如下: https://wm.makeding.com/iclk/?zoneid55982 音乐制作人&#xff1a…

记录关于智能家居的路程的一个bug___Segmentation fault(段错误)

前言 其实发生段错误的情况有很多&#xff1a; 其实在项目的开发中最有可能的错误就是①和②&#xff0c;考虑到本项目数组用的比较少&#xff0c;所以主要是考虑错误①指针的误用。 有时候错误就是那么离谱&#xff0c;声音也算是一种设备&#xff1f;&#xff1f;&#xff…

【安全用电管理系统的应用如何保证用电安全】Acrel-6000安科瑞智慧安全用电解决方案

政策背景 国家部委 ※2017年5月3日国务院安委会召开电气火灾综合治理工作视频会议&#xff0c;决定在全国范围内组织开展为期3年的电气火灾综合治理工作。 公安部领导 ※公安部副部长李伟强调&#xff1a;向科技要战斗力&#xff0c;加快推进“智慧消防”建设不断提升火灾防控…

大创项目推荐 深度学习 opencv python 实现中国交通标志识别_1

文章目录 0 前言1 yolov5实现中国交通标志检测2.算法原理2.1 算法简介2.2网络架构2.3 关键代码 3 数据集处理3.1 VOC格式介绍3.2 将中国交通标志检测数据集CCTSDB数据转换成VOC数据格式3.3 手动标注数据集 4 模型训练5 实现效果5.1 视频效果 6 最后 0 前言 &#x1f525; 优质…

【LeetCode热题100】739. 每日温度(栈)

一.题目要求 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 二.题目难度…

pytest--python的一种测试框架--request请求加入headers

一、request headers中的cookie和session机制的作用与区别 Cookie 和 Session 是两种在客户端和服务器之间保持状态的技术。HTTP 协议本身是无状态的&#xff0c;这意味着服务器无法从上一次的请求中保留任何信息到下一次请求。Cookie 和 Session 机制就是为了解决这个问题。 …

【CASS精品教程】CASS11.0基于离散点创建三维地形(Tin、Grid、等高线)

文章目录 一、打开数据二、创建不规则三角网TIN三、创建等高线CONTOUR四、规则格网GRID五、专栏配套实验数据包下载一、打开数据 打开CASS11软件,点击【绘图处理】→【展野外测点点号】,选择实验数据(实验数据在文末有下载地址),如下图所示: 展点如下图所示(此数据为美国…

搜索与图论——Dijkstra算法求最短路

最短路算法 稠密图与稀疏图 n为点数&#xff0c;m为边数。m远小于n的平方为稀疏图&#xff0c;m接近n的平方为稠密图。 稀疏图用邻接表存&#xff0c;稠密图用邻接矩阵存 朴素版dijkstra时间复杂度为O(n^2),对于稠密图可以ac&#xff0c;但遇到稀疏图时会TLE。 dijkstra函数实…

蓝桥杯算法题-图形排版

题目描述 小明需要在一篇文档中加入 N 张图片&#xff0c;其中第 i 张图片的宽度是 Wi&#xff0c;高度是 Hi。   假设纸张的宽度是 M&#xff0c;小明使用的文档编辑工具会用以下方式对图片进行自动排版&#xff1a; 1. 该工具会按照图片顺序&#xff0c;在宽度 M 以内&…

「Android高级工程师」BAT大厂面试基础题集合-下-Github标星6-5K

C、 com.android.provider.contact D、 com.android.provider.contacts 11.下面关于ContentProvider描述错误的是&#xff08;&#xff09;。 A、 ContentProvider可以暴露数据 B、 ContentProvider用于实现跨程序共享数据 C、 ContentProvider不是四大组件 D、 ContentP…

与webpack类似的工具还有哪些?区别?

文章目录 一、模块化工具二、详细对比RollupParcelSnowpackVitewebpack 参考文献 一、模块化工具 模块化是一种处理复杂系统分解为更好的可管理模块的方式 可以用来分割&#xff0c;组织和打包应用。每个模块完成一个特定的子功能&#xff0c;所有的模块按某种方法组装起来&a…

stitcher类实现多图自动拼接

效果展示 第一组&#xff1a; 第二组&#xff1a; 第三组&#xff1a; 第四组&#xff1a; 运行代码 import os import sys import cv2 import numpy as npdef Stitch(imgs,savePath): stitcher cv2.Stitcher.create(cv2.Stitcher_PANORAMA)(result, pano) stitcher.st…

P-MapNet:Far-seeing Map Generator Enhanced by both SDMap and HDMap Priors

主页&#xff1a;homepage 参考代码&#xff1a;P-MapNet 动机与出发点 在感知系统中引入先验信息是可以提升静态元素感知网络的上限的&#xff0c;这篇文章对SD地图采用栅格化表示&#xff08;也就是图像形式&#xff09;&#xff0c;之后用CNN网络去抽取栅格化SD地图的信息&…