【MySQL8新特性】窗口函数


提出问题

  1. 如何得到各个部门工资排名前N名员工列表?
  2. 查找各部门每人工资栈部门总工资的百分比?

窗口函数概念

MySQL从8.0版本开始支持窗口函数。窗口函数的作用类似于查询中对数据进行分组,不同的是,分组操作会把分组结果聚合成一条记录,而窗口函数将结果置于每一条记录中

它可以理解为记录集合,窗口函数也就是在满足某种条件的记录集合上执行的特殊函数,对于每条记录都要在此窗口内执行函数

简单来说,窗口函数就是对于查询的每一行,都使用与该行相关的行进行计算

窗口函数使用场景

在需要用到分组统计的结果对每一条记录进行计算的场景下,使用窗口函数更好

窗口函数的分类

  • 静态窗口函数,窗口大小固定,不会因为记录的不同而不同
  • 动态窗口函数,窗口大小会随着记录的不同而变化,这种动态变化的窗口叫滑动窗口

窗口函数总体上可以分为:

  • 序号函数
    • ROW_NUMBER():顺序排序
    • RANK():并列排序,会跳过重复的序号
    • DENSE_RANK():并列排序,不会跳过重复的序号
    • PERCENT_RANK()
  • 分布函数
    • PERCENT_RANK()
    • CUME_DIST()
  • 前后函数
    • LAG(expr,n)
    • LEAD(expr,n)
  • 首尾函数
    • FIRST_VALUE(expr)
    • LAST_VALUE(expr)
  • 其他函数
    • NTH_VALUE(expr,n)
    • NTILE(n)

窗口函数的使用

窗口函数的语法

window_function_name(expression)
OVER (
	[partition_definition]
	[order_definition]
	[frame_definition]
)
  • 窗口函数的一个概念是当前行,当前行属于某个窗口,由OVER关键字用来指定函数执行的窗口范围
    • 如果后面括号中什么都不写,则意味着窗口包含满足WHERE条件的所有行,窗口函数基于所有行进行计算
    • 如果后面括号内容不为空,则由三个参数来设置窗口
      • PARTITION BY子句
      • ORDER BY子句
      • FRAME子句
  • PARTITION BY子句:指定窗口函数按照哪些字段进行分组。分组后,窗口函数可以在每个分组中分别执行
  • ORDER BY子句:按照指定字段进行排序,窗口函数将按照排序后的记录进行编号。可以和PARTITION BY配合使用,也可以单独使用
  • FRAME子句:当前分区的一个子集,用来定义子集的规则,通常用来作为滑动窗口使用

实例

序号函数

准备数据

CREATE TABLE IF NOT EXISTS numbers(
num INT
);

INSERT INTO numbers
VALUES (1),(1),(2),(3),(5),(5),(5),(6),(9),(7),(7),(8);

ROW_NUMBER()

SELECT num, ROW_NUMBER() OVER(ORDER BY num)
FROM numbers;

在这里插入图片描述

RANK()

SELECT num, RANK() OVER(ORDER BY num)
FROM numbers;

在这里插入图片描述

DENSE_RANK()

SELECT num, DENSE_RANK() OVER(ORDER BY num)
FROM numbers;

在这里插入图片描述

PERCENT_RANK()

SELECT num, PERCENT_RANK() OVER(ORDER BY num)
FROM numbers;

在这里插入图片描述

前后函数

准备数据

TRUNCATE TABLE numbers;

INSERT INTO numbers
VALUES (1),(2),(3),(5),(6),(9),(7),(8);

SELECT * FROM numbers;

LAG(expr,n)

SELECT num, LAG(num,2) OVER(ORDER BY num)
FROM numbers;

在这里插入图片描述

LEAD(expr,n)

SELECT num, LEAD(num,2) OVER(ORDER BY num)
FROM numbers;

在这里插入图片描述

首尾函数

准备数据

CREATE TABLE IF NOT EXISTS table1(
f1 CHAR(1),
f2 INT
);

DESC table1;

INSERT INTO table1
VALUES ('b',4),('a',1),('c',10),('a',2),('b',3);

SELECT * FROM table1;

FIRST_VALUE(expr)

SELECT 
	f1,
	f2,
	FIRST_VALUE(f2) OVER(PARTITION BY f1)
FROM table1;

在这里插入图片描述

SELECT 
	f1,
	f2,
	FIRST_VALUE(f2) OVER(PARTITION BY f1 ORDER BY f2)
FROM table1;

在这里插入图片描述

LAST_VALUE()

SELECT 
	f1,
	f2,
	LAST_VALUE(f2) OVER(PARTITION BY f1 ORDER BY f2)
FROM table1;

在这里插入图片描述

其他函数

准备数据

CREATE TABLE IF NOT EXISTS numbers(
num INT
);

INSERT INTO numbers
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9);

SELECT * FROM numbers;

NTH_VALUE(expr,n)

SELECT 
	num,
	NTH_VALUE(num,7) OVER()
FROM numbers;

在这里插入图片描述

SELECT 
	num,
	NTH_VALUE(num,11) OVER()
FROM numbers;

在这里插入图片描述

SELECT 
	num,
	NTH_VALUE(num,0) OVER()
FROM numbers;

在这里插入图片描述

NTILE(n)

SELECT 
	num,
	NTILE(6) OVER()
FROM numbers;

在这里插入图片描述

小结

窗口函数的特点是可以分组,而且可以在分组内排序。另外,窗口函数不会因为分组而减少原表中的行数,这对我们在原表数据的基础上进行统计和排序非常有用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值