findwindowex子窗口类型有哪几种_SQL-窗口函数

e5551e0b13936c808132a2bfa1f6d8f9.png

479a69e02ae86c522917116f2fe66365.png

一、窗口函数

  1. 含义

窗口函数,也叫OLAP函数(Online Anallytical Processing,联机分析处理),可以对数据库数据进行实时分析处理。窗口函数包含专用窗口函数和聚合函数,两者区别在于,专用窗口函数返回的是每组多行数据,不影响行数。聚合函数只返回的是每组的单行数据。

2. 基本语句

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

2. 窗口函数类型

专用窗口函数:rank,denserank, row_number等

聚合函数:max,min,sum,avg,count等

二、如何使用窗口函数

建立测试表,如下

INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0001','1','86');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0002','1','95');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0003','2','89');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0004','1','83');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0005','2','86');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0006','3','92');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0007','3','86');
INSERT INTO 班级表(学号,班级,成绩)
            VALUES('0008','1','88');

0d03a0a020f98ae7815e52fe30aea3ba.png

每个班级内按成绩排名,得出结果。

select *,
rank() over (partition by 班级
             order by 成绩 desc) as ranking
from 班级表;

fd37b663ba66a704b90839958e472af8.png

我们理解以下窗口函数的sql语句

  1. partition by 用来对表的分组

每个班级内就是按照班级分组,所以partition by 班级

2. order by 对分组后进行排序,默认升序。

按成绩排名,,所以order by 成绩,加了desc是按照成绩降序排列。

分组汇总与窗口函数的区别:

group by分组汇总后会改变表的行数,一行只有一个类别。而partition by和rank 函数不会影响原表的行数。

/*group by 分组汇总改变行数*/
select 班级,count(学号)
from 班级表
group by 班级
order by 班级;

5ecf5a02a7781ec0677c80dd0946bb3b.png
/*partition by 分组汇总总行数不变*/
select 班级,
count(学号) over (partition by 班级
                  order by 班级) as current_count
from 班级表;

9941c9cd50c784da33a25a7e20ea33c8.png

三、专用窗口函数

rank :跳跃排序,相同数据排名相同,排名存在重复值。

dense_rank :连续排序,相同数据排排名相同。

row_number :相同数据,在前面的排名优先,没有重复值。

select *,
rank() over (order by 成绩 desc ) as ranking,
dense_rank() over (order by 成绩 desc) as dense_ranking,
row_number() over (order by 成绩 desc) as row_num
from 班级表;

898520010f9d1d873b945d90aefcc8b9.png

注意事项:

  1. 窗口函数as后面的别名不能跟函数重名,不然会报错。
  2. 记得窗口函数over后面加括号。

应用:面试经典排名问题

三、聚合窗口函数

  1. 含义

聚合窗口函数和专用窗口函数用法一样,只需把聚合函数放在窗口函数的位置,但是函数后面要指定聚合的列名。

2. sql语句应用

select *,
sum(成绩) over (order by 学号)as current_sum,
avg(成绩) over (order by 学号)as current_avg,
count(成绩) over (order by 学号)as current_count,
max(成绩) over (order by 学号)as current_max,
min(成绩) over (order by 学号)as current_min
from 班级表;

fef6e80622cb3448ad89f004ed7bedd6.png

针对自身记录,以及自身记录之上的数据进行计算。比如:先按学号排序,current_sum列的每行数据是前面所有行数据的总和。current_max列的每行数据是对比前面所有行数据后取最大值。

3. 作用

可以在每一行的数据里直观的看到,截至到本行数据,统计数据是多少。同时可以看出每行数据,对整体统计数据的影响。

四、经典面试题

1. 排名问题

考察的是rank、dense_rank、row_number的区别。具体如何使用请回顾第二部分的专用窗口函数。

2. topN问题

经常遇到的业务问题:

如何找到每个类别下用户最喜欢的产品是哪个?

如果找到每个类别下的用户点击最多的5个商品是什么?

其实就是:分组取每组最大值、最小值,每组最大的N条记录。

案例:按课程号分组提取成绩最大值所在行的数据。

建立测试表score1:

8f1600bab6c2483b6c34bd87a1671ffe.png
  • 方法1:若使用group by分组和汇总函数,可得每个组的一个值,但是无法取得成绩最大值所在行的数据。需要结合关联子查询来实现。
select *
from score1 as a
where 成绩=(select max(成绩) from score1 as b
            where a.课程号=b.课程号);

ff765069efbd08eee8b8c30b3998f62a.png
  • 方法 2:运用窗口函数
select *
from (select *,
      dense_rank() over(partition by 课程号 order by 成绩 desc)as dense_ranking from score1) as a
where dense_ranking=1;

5cfa8dc5abdcf20b64634e5320700cd6.png

topN问题的万能模板:

select * from 
(select *,
row_number() over (partition by 要分组的列名 order by 要排序的列名 desc) as ranking 
from 表名) as a
where ranking <= N;

3. 累计求和问题

案例1:按照雇员编号升序排列,查找薪水的累计薪水。其中累计薪水是前N个当前员工(结束日期=‘9999-01-01‘)薪水的累计和。

select 雇员编号,薪水,
sum(薪水) over (order by 雇员编号) as 累计薪水 
from 薪水表
where 结束时间='1/1/9999';

343a2af6954db8058b36a1534e949c5f.png

案例2:下表为确诊人数表,包含日期和该日期对应的新增确诊人数。

50d394e08a360e8ebac0a8999ae57e7f.png

按照日期进行升序排列,查找日期、确认人数以及对应的累计确诊人数。

select 日期, 确诊人数,
sum(确诊人数) over (order by 日期) as 累计确诊人数
from 确诊人数表;

d5af5007bcaf120765524c13cb3f5744.png

累计求和问题的万能模板:

select 列1,列2,
sum(列名) over (order by 用于排序的列名) as 累计值别名 
from 表名;

4. 如何在每个组里比较。

各科成绩表为如下:

058e2868c1f156331398205a9922b834.png

查找单科成绩高于该科目平均成绩的学生名单。

select 姓名,科目,
avg(成绩) over (partition by 科目) as 平均成绩
from 各科成绩表
where 成绩>平均成绩;

!!!sql报错!!!

原因是在运行顺序中,select字句是最后被运行,该sql是先运行where后select。

正确sql语句写法:

select *
from (select *, avg(成绩) over (partition by 科目) as 平均成绩
from 各科成绩表) as a
where 成绩>平均成绩;

6668fea1c93dbc82f64688ba31a14c26.png

方法二:运用关联子查询。

select 姓名,科目,成绩
from 各科成绩表 a
where 成绩>(select avg(成绩) from 各科成绩表 as b where a.科目=b.科目);

五、窗口函数的移动平均(rows和preceding)

以班级表为测试表。

73dbf1dc8374673213ab9d265564052c.png
select *,
avg(成绩) over (order by 学号 rows 2 preceding) as current_avg
from 班级表;

5c295bd8b52fd8732ebf82d5bca6cb4e.png

rows和precedin是"之前~行"的意思,得出的current_avg数值是自己记录以及前2行的平均值。譬如:学号0004学号的current_avg是自己和前2位同学的平均,即学号0002、0003、0004三位同学的平均。

业务场景:

在公司业绩名单排名中,可以通过移动平均,直观地查看到与相邻名称业绩的平均,求和等统计数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值