窗口函数也叫分析函数
窗口函数的基本用法如下:
其中,over是关键字,用来指定函数执行的窗口范围,包含三个分析子句:分组(partition by)子
句,排序(order by)子句,窗口(rows)子句,如果后面括号中什么都不写,则意味着窗口包含满
足where条件的所有行,窗口函数基于所有行进行计算;如果不为空,则支持以下语法来设置窗口:
知识点总结
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...)
SELECT DATABASES() as 当前数据库名;
SELECT USER() as 用户名;
函数名([expr]) over子句
函数() over()
函数名([expr]) over(partition by <要分列的组> order by <要排序的列> rows
between <数据范围>)
SELECT VERSION() as 数据库版本;A: 需要被加工的字段名称
B: 分组的字段名称
C: 排序的字段名称
D: 计算的行数范围
1.2 窗口函数应用
一般,我们可以把窗口函数分为两种:
专有窗口函数:
rank()
dense_rank()
row_number()
聚合类窗口函数:
普通场景下,聚合函数往往和group by一起使用,但是窗口环境下,聚合函数也可以应
用进来,那么此时它们就被称之为聚合类窗口函数,属于窗口函数的一种
sum()
count()
avg()
max()
min()
窗口函数(专有窗口函数+聚合类窗口函数)和普通场景下的聚合函数也很容易混淆,二者区别
如下:
普通场景下的聚合函数是将多条记录聚合为一条(多到一);窗口函数是每条记录都会执
行,有几条记录执行完还是几条(多到多)。
分组(partition by):记录按照字段进行分组,窗口函数在不同的分组上分别执行。
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
我们可以把窗口函数分为两种:
专有窗口函数:
rank()
dense_rank()
row_number()
聚合类窗口函数:
普通场景下,聚合函数往往和group by一起使用,但是窗口环境下,聚合函数也可以应
用进来,那么此时它们就被称之为聚合类窗口函数,属于窗口函数的一种
sum()
count()
avg()
max()
min()
窗口函数(专有窗口函数+聚合类窗口函数)和普通场景下的聚合函数也很容易混淆,二者区别
如下:
普通场景下的聚合函数是将多条记录聚合为一条(多到一);窗口函数是每条记录都会执
行,有几条记录执行完还是几条(多到多)。
分组(partition by):记录按照字段进行分组,窗口函数在不同的分组上分别执行。
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列名 释义
user_name 用户名
piece 购买数量
price 价格
pay_amount 支付金额
goods_category 商品品类
pay_time 支付日期
排序(order by):按照哪些字段进行排序,窗口函数将按照排序后的记录顺序进行编号,可
以和partition子句配合使用,也可以单独使用。如果没有partition子句,数据范围则是整
个表的数据行。
窗口(rows):就是进行函数分析时要处理的数据范围,属于当前分区的一个子集,通常用来
作为滑动窗口使用。比如要根据每个订单动态计算包括本订单和按时间顺序前后两个订单
的移动平均支付金额,则可以设置rows子句来创建滑动窗口(rows)。
举例:
先创建数据库:
CREATE DATABASE ZXR_2 CHARACTER SET utf8;
先创建表格:
CREATE TABLE user_trade (
user_name VARCHAR ( 20 ),
piece INT,
price DOUBLE,
pay_amount DOUBLE,
goods_category VARCHAR ( 20 ),
pay_time date
);
-- 需求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) '累计金额'
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
b.YEAR,
b.MONTH,
b.pay_amount,
sum( b.pay_amount ) over (
PARTITION BY
b.YEAR
ORDER BY
b.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 ))b;
-- 需求3: 查询出2019年每个月的近三月移动平均支付金额
SELECT
b.MONTH,
b.pay_amount,
AVG( b.pay_amount ) over (
ORDER BY
b.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 ))b;
-- 需求4: 查询出每四个月的最大月总支付金额
SELECT
b.MONTH,
b.pay_amount,
max( b.pay_amount ) over (
ORDER BY
b.MONTH rows BETWEEN 3 preceding and current row)
FROM
(
SELECT
substr(pay_time,1,7) month,
SUM( pay_amount ) pay_amount
FROM
user_trade
WHERE
YEAR ( pay_time ) in (2018,2019)
GROUP BY
substr(pay_time,1,7))b;