赞
踩
窗口函数 (开窗函数),也叫OLAP函数 (OnlineAnallytical Processing,联机分析处理,可以对数据库据
进行实时分析处理。简单来说,窗口函数指的是over()函数, 它相当于给表新增一列, 至于新增的内容
是什么, 取决于窗口函数, 结合什么函数一起使用.
可以结合窗口函数一起使用的函数 over(partition by 分组字段 order by 排序字段 asc | desc rows
between 起始行 and 结束行)
1. partition by类似千聚合函数中的 group by句子,但是在窗口函数中,要写成partition by
2 order by:和普通查询语句中的 ORDER BY没什么不同
聚合函数: count(), sum(), max(), min(), avg()
排序函数: row_number(), rank(), dense_rank(), ntile(数字)
其它函数: lag(), lead(), first_value(), last_value()
1. 窗口函数, 相当于给表新增一列, 至于新增内容是什么, 取决于窗口函数, 结合什么函数一起使用.
2. 如果不写partition by, 则是全局统计, 如果写了, 则是局部统计(即: 只统计该分组的数据)
3. 如果不写order by, 则统计组内所有的数据, 如果写了, 则统计组内第一行 至 当前行的数据.
4. rows between ... and...可以指定操作行的范围, 包左包右,
涉及到的关键字如下:
unbounded preceding # 表示: 第1行.
n preceding # 向上的n行
current row # 当前行.
n following # 向下的n行
unbounded following # 表示: 最后1行.
5. ntile(数字) 表示把数据分成几份, 即: 几分之几, 优先参考最小分区. 例如: 7条数据, 操作之后, 就
是: 1, 1, 1 2, 2 3, 3
- # 员工表
- CREATE TABLE employee
- (
- id int, # 编号
- name varchar(20), # 姓名
- deg varchar(20), # 职位
- salary int, # 工资
- dept varchar(20) # 部门
- );
-
- insert into employee value (1201, 'gopal', 'manager', 50000, 'TP');
- insert into employee value (1202, 'manisha', 'cto', 50000, 'TP');
- insert into employee value (1203, 'khalil', 'dev', 30000, 'AC');
- insert into employee value (1204, 'prasanth', 'dev', 30000, 'AC');
- insert into employee value (1206, 'kranthi', 'admin', 20000, 'TP');
-
- # 网站点击量表
- create table website_pv_info
- (
- cookieid varchar(20), # 用户id
- createtime varchar(20), # 访问时间
- pv int # 页面浏览量
- );
-
- insert into website_pv_info value ('cookie1', '2018-04-10', 1);
- insert into website_pv_info value ('cookie1', '2018-04-11', 5);
- insert into website_pv_info value ('cookie1', '2018-04-12', 7);
- insert into website_pv_info value ('cookie1', '2018-04-13', 3);
- insert into website_pv_info value ('cookie1', '2018-04-14', 2);
- insert into website_pv_info value ('cookie1', '2018-04-15', 4);
- insert into website_pv_info value ('cookie1', '2018-04-16', 4);
- insert into website_pv_info value ('cookie2', '2018-04-10', 2);
- insert into website_pv_info value ('cookie2', '2018-04-11', 3);
- insert into website_pv_info value ('cookie2', '2018-04-12', 5);
- insert into website_pv_info value ('cookie2', '2018-04-13', 6);
- insert into website_pv_info value ('cookie2', '2018-04-14', 3);
- insert into website_pv_info value ('cookie2', '2018-04-15', 9);
- insert into website_pv_info value ('cookie2', '2018-04-16', 7);
-
- # 网站访问记录表
- create table website_url_info
- (
- cookieid varchar(20), # 用户id
- createtime varchar(20), # 访问时间
- url varchar(20) # 访问的url页面
- );
- insert into website_url_info value ('cookie1', '2018-04-10 10:00:02', 'url2');
- insert into website_url_info value ('cookie1', '2018-04-10 10:00:00', 'url1');
- insert into website_url_info value ('cookie1', '2018-04-10 10:03:04', '1url3');
- insert into website_url_info value ('cookie1', '2018-04-10 10:50:05', 'url6');
- insert into website_url_info value ('cookie1', '2018-04-10 11:00:00', 'url7');
- insert into website_url_info value ('cookie1', '2018-04-10 10:10:00', 'url4');
- insert into website_url_info value ('cookie1', '2018-04-10 10:50:01', 'url5');
- insert into website_url_info value ('cookie2', '2018-04-10 10:00:02', 'url22');
- insert into website_url_info value ('cookie2', '2018-04-10 10:00:00', 'url11');
- insert into website_url_info value ('cookie2', '2018-04-10 10:03:04', '1url33');
- insert into website_url_info value ('cookie2', '2018-04-10 10:50:05', 'url66');
- insert into website_url_info value ('cookie2', '2018-04-10 11:00:00', 'url77');
- insert into website_url_info value ('cookie2', '2018-04-10 10:10:00', 'url44');
- insert into website_url_info value ('cookie2', '2018-04-10 10:50:01', 'url55');
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- # 案例1: 窗口函数初体验.
- # 需求: 统计每个所有员工的工资, 并将其展示在每个员工数据的最后.
- # 思路1: 聚合函数直接实现, 能计算出: 所有员工的工资总和, 但是无法达到想要的效果.
- select *, sum(salary) as total_salary from employee;
-
- # 思路2: 窗口函数可以实现我们要的效果.
- select *, sum(salary) over() as total_salary from employee;
- select * from employee;
- # 案例2: 演示 窗口函数 + 聚合函数一起使用.
- # 需求:求出网站总的pv数 所有用户所有访问加起来
- select *, sum(pv) over() from website_pv_info; # 不写partition by, 全局统计(统计表中所有的数据)
-
- # 需求: 求出每个用户总pv数
- # 方式1: sum() + group by 一起使用.
- select cookieid, sum(pv) as total_pv from website_pv_info group by cookieid;
-
- # 方式2: 聚合函数 + 窗口函数一起使用.
- select *, sum(pv) over(partition by cookieid) from website_pv_info; # 写partition by, 局部统计(只统计该分组的数据.)
-
- # 演示: 如果不写order by, 则统计组内所有的数据, 如果写了, 则统计组内第一行 至 当前行的数据.
- select *, sum(pv) over(partition by cookieid order by createtime) from website_pv_info; # 写order by, 局部统计(统计组内第一行 至 当前行的内容)
- # 上述的代码, 等同于:
- select
- *,
- sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row ) as n1 # 起始行 到 当前行
- from website_pv_info; # 写order by, 局部统计(统计组内第一行 至 当前行的内容)
-
- # 需求: 统计每个cookieID的pv(访问量), 只统计: 当前行及 向前3行 向后1行
- select
- *,
- sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following)
- from website_pv_info; # 写order by, 局部统计(统计组内第一行 至 当前行的内容)
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- # 需求: 根据点击量(pv)做排名. 根据cookieid分组, 根据点击量降序排名.
- select
- *,
- # 根据cookieid分组, 根据点击量降序排名.
- row_number() over(partition by cookieid order by pv desc) as rn, # 例如: 排名为: 1, 2, 3, 4
- rank() over(partition by cookieid order by pv desc) as rk, # 例如: 排名为: 1, 2, 2, 4
- dense_rank() over(partition by cookieid order by pv desc) as dr # 例如: 排名为: 1, 2, 2, 3
- from website_pv_info;
-
- # ntile(数字,表示分成几份) 采用均分策略, 每份之间的差值不超过1, 优先参考最小的那个部分, 即: 7分成3份, 则是: 3, 2, 2
- select
- *,
- # 根据cookieid分组, 根据点击量降序排名.
- ntile(3) over(partition by cookieid order by pv desc) as nt
- from website_pv_info;
-
- # 上述的ntile()是将数据分成指定的 份数, 方便我们取样(采样), 例如: 将数据按组分成5份, 只获取每组的第1份数据, 则计算量的数据量至少降低 5 倍.
- # 例如: 上述的数据是分成了3份, 如果我要每组的第一份怎么办? 子查询.
- select * from (
- select *,
- # 根据cookieid分组, 根据点击量降序排名.
- ntile(3) over (partition by cookieid order by pv desc) as nt
- from website_pv_info
- ) t1 where t1.nt = 1;
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- # 1. LAG 用于统计窗口内往上第n行值
- select
- *,
- # 获取上一行的createtime类的值 根据cookieid分组 根据创建时间排序
- lag(createtime) over(partition by cookieid order by createtime)
- from website_url_info;
-
- # 完整写法如下
- select
- *,
- # lag()函数的参数解释: 参1 要操作的列, 参2: 向上的第n行, 参3: 默认值,找不到数据的时候, 用默认值填充.
- lag(createtime, 2, '1970-01-01 00:00:00') over(partition by cookieid order by createtime)
- from website_url_info;
-
- # 2. LEAD 用于统计窗口内往下第n行值
- select
- *,
- # LEAD()函数的参数解释: 参1 要操作的列, 参2: 向上的第n行, 参3: 默认值,找不到数据的时候, 用默认值填充.
- LEAD(createtime, 2, '1970-01-01 00:00:00') over(partition by cookieid order by createtime)
- from website_url_info;
-
-
- # 3. FIRST_VALUE 取分组内排序后,截止到当前行,第一个值
- select
- *,
- first_value(createtime) over(partition by cookieid order by createtime)
- from website_url_info;
-
- # 4. LAST_VALUE 取分组内排序后,截止到当前行,最后一个值
- select
- *,
- last_value(createtime) over(partition by cookieid order by createtime)
- from website_url_info;
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1.窗口函数的功能
①同时具有分组 (partition by)和排序 (order by)的功能
② 不减少原表的行数
2.窗口函数的执行顾序
在使用over等开窗函数时,over(里的分组以及排序的执行,晚于 where、group by、 order by的执行。
3. 窗口函数的使用场景
①组内排名
②求占比
③ TopN问题
4. 注意事项
①窗口函数原则上只能写在select子句中。
②partition子句原则上可是省略,省略就是 不指定分组。但是,这就失去了窗口函数的功能,所以一般不要这么使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。