Mysql窗口函数

1 什么是窗口函数

MySQL从8.0开始支持窗口函数,有的也叫分析函数(处理相对复杂的报表统计分析场景),这个功能在大多商业数据库和部分开源数据库中早已支持。

窗口函数:窗口、函数(应用在窗口内的函数)-----窗口类似于窗户,限定一个空间范围

那什么叫窗口呢?

窗口的概念非常重要,它可以理解为记录集合,窗口函数也就是在满足某种条件的记录集合上执行的特殊函数。对于每条记录都要在此窗口内执行函数,窗口大小都是固定的,这种属于静态窗口;不同的记录对应着不同的窗口,这种动态变化的窗口叫滑动窗口。

窗口函数的基本用法如下:

函数名([expr]) over 子句
函数() over()

其中,over是关键字,用来指定函数执行的窗口范围,包含三个分析子句:分组(partition by)子句,排序(order by)子句,窗口(rows)子句,如果后面括号中什么都不写,则意味着窗口包含满足where条件的所有行,窗口函数基于所有行进行计算;如果不为空,则支持以下语法来设置窗口:

函数名([expr]) over(partition by <要分列的组> order by <要排序的列> rows
between <数据范围>)
  • 知识点总结

sum(...A...) over(partition by ...B... order by ...C... rows between ...D1... and ...D2...)

avg(...A...) over(partition by ...B... order by ...C... rows between ...D1... and ...D2...)

A: 需要被加工的字段名称

B: 分组的字段名称

C: 排序的字段名称

D: 计算的行数范围

rows between 2 preceding and current row # 取当前行和前面两行

rows between unbounded preceding and current row # 包括本行和之前所有的行

rows between current row and unbounded following # 包括本行和之后所有的行

rows between 3 preceding and current row # 包括本行和前面三行

rows between 3 preceding and 1 following # 从前面三行和下面一行,总共五行

# 当order by后面缺少窗口从句条件,窗口规范默认是rows between unbounded preceding and current row.

# 当order by和窗口从句都缺失, 窗口规范默认是 rows between unbounded preceding and unbounded following

2 窗口函数应用

一般,我们可以把窗口函数分为两种:

专有窗口函数:

  • rank()
  • dense_rank()
  • row_number()

聚合类窗口函数:

普通场景下,聚合函数往往和group by一起使用,但是窗口环境下,聚合函数也可以应 用进来,那么此时它们就被称之为聚合类窗口函数,属于窗口函数的一种

  • sum()
  • count()
  • avg()
  • max()
  • min()

窗口函数(专有窗口函数+聚合类窗口函数)和普通场景下的聚合函数也很容易混淆,二者区别如下:

  • 普通场景下的聚合函数是将多条记录聚合为一条(多到一);窗口函数是每条记录都会执行,有几条记录执行完还是几条(多到多)。
  • 分组(partition by):记录按照字段进行分组,窗口函数在不同的分组上分别执行。
  • 排序(order by):按照哪些字段进行排序,窗口函数将按照排序后的记录顺序进行编号,可以和partition子句配合使用,也可以单独使用。如果没有partition子句,数据范围则是整 个表的数据行。
  • 窗口(rows):就是进行函数分析时要处理的数据范围,属于当前分区的一个子集,通常用来作为滑动窗口使用。比如要根据每个订单动态计算包括本订单和按时间顺序前后两个订单的移动平均支付金额,则可以设置rows子句来创建滑动窗口(rows)。

现有2018~2020某电商平台订单信息表user_trade

表结构如下:

列名释义
user_name用户名
piece购买数量
price价格
pay_amount支付金额
goods_category商品品类
pay_time支付日期
# 建立数据表
use legou;
create table user_trade
(
    user_name varchar(20),
    piece int,
    price double,
    pay_amount double,
    goods_category varchar(20),
    pay_time date
);

查看前10行数据

------累计计算函数应用、排序函数应用、偏移分析函数应用

2.1 累计计算函数

  • 累计求和:sum() over()
需求1: 查询出2019年每月的支付总额和当年累积支付总额
/*
需求1: 查询出2019年每月的支付总额和当年累积支付总额
*/

-- step1 过滤出2019年数据
select * from user_trade where year(pay_time)=2019;

-- step2 在1的基础上,按照月份进行group by 分组,统计每个月份的支付总额
SELECT 
    MONTH( pay_time ),
    sum( pay_amount )
FROM
    user_trade
WHERE
    YEAR ( pay_time ) = 2019
GROUP BY
    MONTH ( pay_time );

-- step3 在2的基础上应用窗口函数实现需求
SELECT
    a.MONTH,-- 月份
    a.pay_amount,-- 当月总支付金额
    sum( a.pay_amount ) over ( ORDER BY a.MONTH ) -- 就是2019年的数据,所以
不用分组
-- --此时没有使用rows指定窗口数据范围,默认当前行及其之前的所有行
    FROM
        (
    SELECT 
        MONTH( pay_time ) MONTH,
        sum( pay_amount ) pay_amount
    FROM
        user_trade
    WHERE
        YEAR ( pay_time ) = 2019
    GROUP BY
        MONTH ( pay_time )
    ) a

结果如下:

需求2:查询出2018-2019年每月的支付总额和当年累积支付总额
SELECT a.year,
a.month,
a.pay_amount,
sum(a.pay_amount) over(partition by a.year order by a.month)
FROM
(SELECT year(pay_time) year,
month(pay_time) month,
sum(pay_amount) pay_amount
FROM user_trade
WHERE year(pay_time) in (2018,2019)
GROUP BY year(pay_time),
month(pay_time))a;

结果如下:

  • 移动平均:avg() over()
需求3: 查询出2019年每个月的近三月移动平均支付金额
SELECT a.month,
       a.pay_amount,
       avg(a.pay_amount) over(order by a.month rows between 2 preceding
and current row)
FROM
       (SELECT month(pay_time) month,
        sum(pay_amount) pay_amount
        FROM user_trade
        WHERE year(pay_time)=2019
        GROUP BY month(pay_time))a;

结果如下:

  • 最大/小值:max()/min() over()
需求4: 查询出每四个月的最大月总支付金额
SELECT a.month,
       a.pay_amount,
       max(a.pay_amount) over(order by a.month rows between 3 preceding
and current row)
FROM
       (SELECT substr(pay_time,1,7) as month,
       sum(pay_amount) as pay_amount
       FROM user_trade
       GROUP BY substr(pay_time,1,7))a;

结果如下;

2.2 排序函数

  • row_number() over(......)
  • rank() over(......)
  • dense_rank() over(......)
需求5: 2020年1月,购买商品品类数的用户排名
/*
需求5: 2020年1月,购买商品品类数的用户排名
2020年1月(基础数据范围)
一个商品属于某一个品类
A用户购买了100件商品,那么可能涉及到了10个品类
B用户购买了50件商品,那么可能涉及到了15个品类
根据所购买商品涉及的品类数量进行排名(给用户)
思路:
1)先把各个用户所购买商品涉及的品类数给统计出来
2) 在1的基础上排名,使count()用到排名窗口函数
*/

-- 1)先把各个用户所购买商品涉及的品类数给统计出来
SELECT
    user_name,
    count( DISTINCT goods_category ) category_count,
    row_number() over(order by count( DISTINCT goods_category ) ) order1,
-- row_number生成了行的编号从1开始
    rank() over(order by count( DISTINCT goods_category ) ) order2,
    dense_rank() over(order by count( DISTINCT goods_category ) ) order3
FROM
    user_trade
WHERE
    substring( pay_time, 1, 7 ) = '2020-01'
GROUP BY
    user_name;

结果如下:

  • 知识点总结

这三个函数的作用都是返回相应规则的排序序号

row_number() over(partition by ...A... order by ...B... )

rank() over(partition by ...A... order by ...B... )

dense_rank() over(partition by ...A... order by ...B... )

A:分组的字段名称

B:排序的字段名称

注意:

  • row_number()、rank() 和dense_rank()紧邻的括号内是不加任何字段名称的。
  • row_number:它会为查询出来的每一行记录生成一个序号,依次排序且不会重复。
  • rank&dense_rank:如果使用rank函数来生成序号,over子句中排序字段值相同的序号是一样 的,后面字段值不相同的序号将跳过相同的排名号排下一个,也就是相关行之前的排名数加一。
  • dense_rank函数在生成序号时是连续的,而rank函数生成的序号有可能不连续。
  • dense_rank函数出现相同排名时,将不跳过相同排名号,rank值紧接上一次的rank值。
  • 在各个分组内,rank()是跳跃排序,有两个第一名时接下来就是第三名,dense_rank()是连续排 序,有两个第一名时仍然跟着第二名。

  • ntile(n) over(......)
需求6: 查询出将2020年2月的支付用户,按照支付金额分成5组后的结果
SELECT user_name,
    sum(pay_amount) pay_amount,
    ntile(5) over(order by sum(pay_amount) desc) level
FROM user_trade
WHERE substr(pay_time,1,7)='2020-02'
GROUP BY user_name;

结果如下:

需求7: 查询出2020年支付金额排名前30%的所有用户
SELECT a.user_name,
       a.pay_amount,
       a.level
FROM
       (SELECT user_name,
               sum(pay_amount) pay_amount,
               ntile(10) over(order by sum(pay_amount) desc) level
        FROM user_trade
        WHERE year(pay_time)=2020
        GROUP BY user_name)a
WHERE a.level in (1,2,3);

结果如下:

  • 知识点总结

ntile(n) over(partition by ...A... order by ...B... )

n:切分的片数

A:分组的字段名称

B:排序的字段名称

ntile(n),用于将分组数据按照顺序切分成n片,返回当前切片值 NTILE不支持ROWS BETWEEN。

2.3 偏移分析函数

  • lag(...) over(......)
  • lead(...) over(......)
需求8: 查询出King和West的时间偏移(前N行)
SELECT user_name,
       pay_time,
       lag(pay_time,1,pay_time) over(partition by user_name order by pay_time) lag1,
       -- 没有传入偏移量,那么默认就是1,找不到的话,此处也没有给默认值,为null
       lag(pay_time) over(partition by user_name order by pay_time) lag1_s,
       lag(pay_time,2,pay_time) over(partition by user_name order by pay_time) lag2,
       lag(pay_time,2) over(partition by user_name order by pay_time) lag2_s
FROM user_trade
WHERE user_name in ('King','West');

结果如下:

需求9: King和West的时间偏移(后N行)
SELECT user_name,
       pay_time,
       lead(pay_time,1,pay_time) over(partition by user_name order by pay_time) lead1,
       lead(pay_time) over(partition by user_name order by pay_time) lead2,
       lead(pay_time,2,pay_time) over(partition by user_name order by pay_time) lead3,
       lead(pay_time,2) over(partition by user_name order by pay_time) lead4
FROM user_trade
WHERE user_name in ('King','West');

结果如下:

  • 知识点总结

Lag和Lead函数可以在同一次查询中取出同一字段的前N行的数据(Lag)和后N行的数据(Lead) 作为独立的列。

在实际应用当中,若要用到取今天和昨天的某字段差值时,Lag和Lead函数的应用就显得尤为重要。 lag(exp_str,offset,defval) over(partion by ......order by ......)

lead(exp_str,offset,defval) over(partion by ......order by ......)

exp_str是字段名称。 offset是偏移量,即是上1个或上N个的值,假设当前行在表中排在第5行,则offset 为3,则表示我们所要找的数据行就是表中的第2行(即5-3=2)。offset默认值为1。defval默认值,当两个函数取上N/下N个值,当在表中从当前行位置向前数N行已经超出了表的范围时,lag()函数将defval这个参数值作为函数的返回值,若没有指定默认值,则返回NULL,那么在数学运算中,总要给一个默认值才不会出错。

  • 补充练习:
 需求10: 查询出支付时间间隔超过100天的用户数
SELECT count(distinct user_name)
FROM
       (SELECT user_name,
               pay_time,
               lead(pay_time) over(partition by user_name order by pay_time) lead_dt
       FROM user_trade)a
WHERE a.lead_dt is not null
and datediff(a.lead_dt,a.pay_time)>100;

结果如下:

需求11: 查询出每年支付时间间隔最长的用户
SELECT
       years,
       b.user_name,
       b.pay_days
FROM
   (SELECT
            years,
            a.user_name,
            datediff(a.pay_time,a.lag_dt) pay_days,
            rank() over(partition by years order by datediff(a.pay_time,a.lag_dt) desc) rank1
   FROM
       (SELECT
                year(pay_time) as years,
                user_name,
                pay_time,
                lag(pay_time) over(partition by user_name,year(pay_time) order by pay_time) lag_dt
         FROM user_trade)a
   WHERE a.lag_dt is not null)b
WHERE b.rank1=1;

结果如下:

发布于 2023-07-19 09:21・IP 属地上海

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Dockerfile与Docker网络

一、Dockerfile 1、概念&#xff1a; Dockerfile是用来构建docker镜像的文本文件&#xff0c;是由构建镜像所需要的指令和参数构建的脚本。 2、构建步骤&#xff1a; ① 编写Dockerfile文件 ② docker build命令构建镜像 ③ docker run依据镜像运行容器实例 Dockerfile …

深入理解:Class.getResource与ClassLoader.getResource使用区别

深入理解&#xff1a;Class.getResource与ClassLoader.getResource使用区别 一作用&#xff1a;都是使用类的类加载器来读取某个文件&#xff0c;从而获取该文件的URL对象二Class.getResource()方法读取文件&#xff1a;1.若文件路径以“/”开头&#xff0c;则该方法会从classp…

洛谷 P9516 color C++代码

目录 前言 思路点拨 AC代码 结尾 前言 今天我们来做洛谷上的一道题目。 网址&#xff1a;color - 洛谷 题目&#xff1a; 思路点拨 这题就是if-else判断输入的五个数据和不就OK了&#xff1f; 在这里我的估值是183&#xff08;截止2023.12.3&#xff09;&#xff0c;热…

软件工程单选多选补充

2. 4. 5. 6. 7. 8. 9. 10. 12。 13.

Zabbix监控接收SNMPTrap消息与SNMPTT结合

一.SNMP 协议 1.协议介绍 snmp 协议是日常使用的较多的一种协议&#xff0c;绝大多数网络设备/存储等都支持 snmp 协议&#xff0c;通过此协议可以实现设备状态的监控及管理。 2.主要组成 SNMP 协议包括以下三个部分: SNMP Agent&#xff1a;负责处理 snmp 请求&#xff0c…

k8s中批量处理Pod应用的Job和CronJob控制器、处理守护型pod的DaemonSet控制器介绍

目录 一.Job控制器 1.简介 2.Jobs较完整解释 3.示例演示 4.注意&#xff1a;如上例的话&#xff0c;执行“kubectl delete -f myJob.yaml”就可以将job删掉 二.CronJob&#xff08;简写为cj&#xff09; 1.简介 2.CronJob较完整解释 3.案例演示 4.如上例的话&#xf…

应用安全四十三:无密码认证安全

什么是无密码认证&#xff1f; 无密码认证是一种新兴的安全技术和身份认证手段&#xff0c;是用密码以外的东西验证软件用户身份的过程&#xff0c;旨在替代传统的用户账号和密码认证方法&#xff0c;提高账号的安全性和用户体验。无密码技术通过生物识别、多因素认证、基于硬…

长度最小的子数组(Java详解)

目录 题目描述 题解 思路分析 暴力枚举代码 滑动窗口代码 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条…

Prime 1.0

信息收集 存活主机探测 arp-scan -l 或者利用nmap nmap -sT --min-rate 10000 192.168.217.133 -oA ./hosts 可以看到存活主机IP地址为&#xff1a;192.168.217.134 端口探测 nmap -sT -p- 192.168.217.134 -oA ./ports UDP端口探测 详细服务等信息探测 开放端口22&#x…

【Linux】进程控制-进程创建

目录 一、fork()是什么&#xff1f; 二、fork返回值问题 1、fork()的两个返回值是什么&#xff1f; 2、fork()为什么有两个返回值&#xff1f; 3、一个变量为什么会保存两个不同的值&#xff1f; 三、写时拷贝 1、写时拷贝是什么 2、为什么要写时拷贝 3、写时拷贝的示意…

GEE:均值滤波

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine(GEE)平台上,进行均值滤波操作的代码框架、核心函数和多种卷积核。 并分别以林地区域和农田区域为试验区,以NDVI图像为例。结果如下图所示, 文章目录 一、均值滤波二、完整代码三、代码链接一、均值滤波 均值滤…

Docker常用进本命令【必备基本功】

docker常用命令 1.帮助命令 1.查看当前docker 版本 docker version2.查看docker的详细信息 docker info3.docker的帮助命令 docker --help2.镜像命令 镜像命令说明docker images列出本地主机的镜像docker search 镜像名称从docker HUB上搜索镜像docker pull 镜像名称从…

ScyllaDB 基础入门

简介 ScyllaDB 是一种开源的 NoSQL 数据库&#xff0c;它提供了高性能、低延迟的数据处理能力&#xff0c;同时保持了与 Apache Cassandra 高度的兼容性。ScyllaDB 使用了一种名为 “Seastar” 的高效并行编程框架&#xff0c;并采用了 C 进行开发&#xff0c;因此它能够充分利…

Linux 进程状态

操作系统学科的进程状态 新建态&#xff1a;刚刚创建的进程&#xff0c; 操作系统还未把它加入可执行进程组&#xff0c; 它通常是进程控制块已经创建但还未加载到内存中的新进程。就绪态&#xff1a;进程做好了准备&#xff0c;只要有机会就开始执行。阻塞态&#xff1a;进程在…

【富文本编辑器】原生JS使用WangEditor和vue上传图片前后端demo

【富文本编辑器】原生JS使用WangEditor上传图片前后端demo 第一步 HTML 第二步 初始化WangEditor与图片上传回调函数 第三步 后端返回数据体封装 第四步 后端接口上传图片&#xff0c;并返回图片地址 最近&#xff0c;我遇到了这样一个问题&#xff1a;因为我们的项目是基于…

网络和Linux网络_9(应用层和传输层_笔试选择题)

目录 一. 常见应用协议等等 1. 以下不是合法HTTP请求方法的是( ) 2. 文件传输使用的协议是&#xff08;&#xff09; 3. HTTP1.1的请求方法不包括&#xff1f;() 4. http状态码中&#xff0c;( )表示访问成功&#xff0c;( )表示坏请求&#xff0c;( )表示服务不可用。() …

【力扣206】反转链表

【力扣206】反转链表 一.题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1 &#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2 &#xff1a; 输入&#xff1a;head [1,2] 输出&#x…

物奇平台电容触摸功能调试

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 物奇平台电容触摸功能调试 1 修改按键驱动宏 2 编译生成wpk 文件,import 导入烧录文件。…

先遗忘后学习:基于参数计算的大模型知识更新

深度学习自然语言处理 原创作者&#xff1a;陈定纬编辑&#xff1a;cola 最近&#xff0c;大型语言模型&#xff08;LLMs&#xff09;展示了其令人惊叹的文本理解和生成能力。然而&#xff0c;即使是更为强大的LLMs&#xff0c;仍有可能从训练语料库中学到不正确的知识&#xf…

k8s安装学习环境

目录 环境准备 配置hosts 关闭防火墙 关闭交换分区 调整swappiness参数 关闭setlinux Ipv4转发 时钟同步 安装Docker 配置Yum源 安装 配置 启动 日志 安装k8s 配置Yum源 Master节点 安装 初始化 配置kubectl 部署CNI网络插件 Node节点 检查 环境准备 准…
最新文章