• 开窗函数

2.1开窗函数的定义及语法

开窗函数(又名:分析函数,窗口函数,OLAP函数)

聚合函数:将数据按照一定的规则分组,统一分析各组的某项情况,每个分组返回一行结果

开窗函数:将数据按照一定的规则分组,统一分析各组的某项情况,每行数据返回一行结果

( OLTP:事务处理 OLAP:数据分析)

开窗函数的语法形式:分析函数名()OVER(分析子句) --OVER()是开窗函数的一个标志

分析函数名:

1.聚合类:SUM() AVG() MAX() MIN() COUNT() --功能与聚合函数上相同

2.排序类:ROW_NUMBER() RANK() DENSE_RANK()

3.偏移类:LAG() LEAD()

分析子句:分组(PARTITION BY) 排序(ORDER BY) 窗口(ROWS) --窗口还有个极少用的RANGE

如何理解是三个分析子句:

1)例如现有多个班级的学生

2)所有学生按照班级分组--PARTITION BY CLASS

3)每个班级的学生按照成绩排座位--ORDER BY SCORE

4)从教室的后窗观察到部分学生的上课状态--ROWS

分析子句并不一定要写,也不一定全部都写,分析子句的使用依照需求和函数类型而定

2.2各类开窗函数举例

--建BUSINESS表,方便接下来的学习

CREATE TABLE BUSINESS(DATE_DT VARCHAR2(20),DAY VARCHAR2(20),WEEK VARCHAR2(20),AMT NUMBER);

--表中插入数据

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-04','星期一','第一周','3000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-05','星期二','第一周','2000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-06','星期三','第一周','1000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-07','星期四','第一周','4000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-08','星期五','第一周','6000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-09','星期六','第一周','2000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-10','星期日','第一周','3000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-11','星期一','第二周','1000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-12','星期二','第二周','4000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-13','星期三','第二周','8000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-14','星期四','第二周','2000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-15','星期五','第二周','5000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-16','星期六','第二周','3000');

INSERT INTO BUSINESS(DATE_DT,DAY,WEEK,AMT) VALUES('2020-05-17','星期日','第二周','7000');

COMMIT;

SELECT * FROM BUSINESS;  --扫描全表

测试表:BUSINESS

聚合类举例:SUM() AVG() MAX() MIN() COUNT()

用法(以SUM为例):SUM(COL_NAME)OVER([PARTITION] [ORDER] [ROWS])

SELECT A.*,SUM(AMT) OVER() FROM BUSINESS A;

SELECT WEEK,SUM(AMT) FROM BUSINESS GROUP BY WEEK;

SELECT A.*,SUM(AMT) OVER(PARTITION BY WEEK) FROM BUSINESS A;

SELECT A.*,SUM(AMT) OVER(ORDER BY DAY) FROM BUSINESS A;

SELECT * FROM BUSINESS;

--查询每天的营业额及整个月的营业额总额

SELECT DATE_DT,AMT,(SELECT SUM(AMT) FROM BUSINESS) FROM BUSINESS;

--查询每天的营业额及每个周的营业额总额

SELECT DATE_DT,AMT,WEEK,SUM(AMT) OVER(PARTITION BY WEEK) A FROM BUSINESS;

--查询每天的营业额及月每日累计营业额

SELECT A.*,SUM(AMT) OVER(ORDER BY DATE_DT) FROM BUSINESS A; --所有数据从第一条到当前数据的和

--查询每天的营业额及周每日累计营业额 

SELECT A.*,SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT) FROM BUSINESS A;--在组内,从第一条到当前数据的和

聚合类开窗函数注意点:

1)分析函数名内必须包含需要分析的内容

2)分析子句没有硬性要求  --出现ROWS时,必须跟随ORDER BY

3)采用默认窗口范围时,下一个相同值(排序的值)会被一并算入

SELECT ENAME,SAL,SUM(SAL) OVER(ORDER BY SAL) FROM EMP;  --相同的值会一并计算入内

排序类举例:ROW_NUMBER() RANK() DENSE_RANK()

用法(以ROW_NUMBER为例):ROW_NUMBER()OVER([PARTITION] ORDER)

SELECT DATE_DT,AMT,AMT-SUM(AMT) OVER(PARTITION BY WEEK) FROM BUSINESS;--当天营业额与周营业额之差

--查询每天的营业额并在整月范围内升序排列

SELECT DATE_DT,AMT,ROW_NUMBER() OVER(ORDER BY AMT) FROM BUSINESS; --如果有相同的,也会按序号往下排(不并列,不跳跃)

SELECT DATE_DT,AMT,RANK() OVER(ORDER BY AMT) FROM BUSINESS; --如果有相同的,会把相同的变成同一个序号,按相同的数量的总数往下一位排(并列跳跃)

SELECT DATE_DT,AMT,DENSE_RANK() OVER(ORDER BY AMT) FROM BUSINESS; --如果有相同的,会把相同的变成同一个序号,下一个不相同的,按这个序号加1往下排(并列不跳跃)

--查询每天的营业额并在每周范围内降序排列

SELECT * FROM BUSINESS;

SELECT DATE_DT,AMT,WEEK,ROW_NUMBER() OVER(PARTITION BY WEEK ORDER BY AMT DESC) FROM BUSINESS;

--排序类开窗函数用于去重

SELECT * FROM BIAO;

SELECT ENAME,BNO,BSEX,ROW_NUMBER() OVER(PARTITION BY ENAME ORDER BY BNO) FROM BIAO;

SELECT DISTINCT ENAME,BNO,BSEX,TT FROM BIAO;  --完全重复去重

SELECT ENAME, BNO, BSEX,TT

FROM (SELECT ENAME,

BNO,

BSEX,TT,

ROW_NUMBER() OVER(PARTITION BY ENAME ORDER BY TT DESC) BR --将名字相同的分为一组,再在这些组里根据日期排序,取出每个组里排第一的的数据

FROM BIAO)

WHERE BR = 1;  --ROW_NUMBER的另一种用法,当多条数据属于某一个人,但数据都不尽相同时(在某些字段上去重,(取最新数据))

--RANK()

SELECT ENAME, BNO, BSEX,TT

FROM (SELECT ENAME,

BNO,

BSEX,TT,

RANK() OVER(PARTITION BY ENAME ORDER BY TT DESC) BR

FROM BIAO)

WHERE BR = 1;

--DENSE_RANK()

SELECT ENAME, BNO, BSEX,TT

FROM (SELECT ENAME,

BNO,

BSEX,TT,

DENSE_RANK() OVER(PARTITION BY ENAME ORDER BY TT DESC) BR --将名字相同的分为一组,再在这些组里根据日期排序,取出每个组里排第一的的数据

FROM BIAO)

WHERE BR = 1;

SELECT * FROM BIAO;

SELECT * FROM BIAO FOR UPDATE;

--注意:用在去重时,一般用ROW_NUMBER(),因为如果用RANK()和DENSE_RANK()的话

--碰到两条一样的数据时排序会一样,而在取出来时也会一并取出来,达不到去重的效果

--写在开窗函数里的ORDER BY 和 写在开窗函数外面的ORDER BY 的区别

写在开窗函数里的ORDER BY是对开窗函数里的数据进行排序

写在开窗函数外面的ORDER BY是对最终的结果进行一个排序

排序类开窗函数注意点:

1)分子函数名内不能包含任何内容  --ROW_NUMBER() 括号内不能包含任何东西

2)分析子句内必须添加ORDER BY,且不能指定窗口  --排序类字句中必须加ORDER BY ,而且不能加ROWS()

偏移类举例:LAG() LEAD()

用法(以LAG为例):LAG(COL_NAME,OFFSET,DEFVAL)OVER():向前偏移N行取数

COL_NAME:要分析的字段

OFFSET:偏移量 --默认偏移一行

DEFVAL:默认返回值 --默认返回空null

--查询每天的营业额以及前一天的营业额

方法1:

SELECT DATE_DT, AMT, LAG(AMT, 1, 0) OVER(ORDER BY DATE_DT) FROM BUSINESS; --更简单

方法2:

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(ORDER BY DATE_DT ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING)

FROM BUSINESS;

--两天营业额之差

SELECT DATE_DT,AMT,AMT-LAG(AMT,1,0) OVER(ORDER BY DATE_DT) FROM BUSINESS;  --偏移量不能为负值

--查询五月连续登录五天的用户

--建表检测

CREATE TABLE EXAM(ID VARCHAR2(10),TS VARCHAR2(15));

INSERT INTO EXAM VALUES('A0001','2021/01/04');

INSERT INTO EXAM VALUES('A0002','2021/01/04');

INSERT INTO EXAM VALUES('A0001','2021/01/05');

INSERT INTO EXAM VALUES('A0003','2021/01/05');

INSERT INTO EXAM VALUES('A0001','2021/01/06');

INSERT INTO EXAM VALUES('A0001','2021/01/07');

INSERT INTO EXAM VALUES('A0001','2021/01/08');

INSERT INTO EXAM VALUES('A0002','2021/01/09');

INSERT INTO EXAM VALUES('A0002','2021/01/10');

INSERT INTO EXAM VALUES('A0003','2021/01/10');

INSERT INTO EXAM VALUES('A0002','2021/01/11');

INSERT INTO EXAM VALUES('A0002','2021/01/12');

INSERT INTO EXAM VALUES('A0002','2021/01/13');

INSERT INTO EXAM VALUES('A0005','2021/01/13');

INSERT INTO EXAM VALUES('A0003','2021/01/14');

INSERT INTO EXAM VALUES('A0004','2021/01/15');

INSERT INTO EXAM VALUES('A0004','2021/01/16');

INSERT INTO EXAM VALUES('A0007','2021/01/17');

INSERT INTO EXAM VALUES('A0008','2021/01/18');

SELECT * FROM EXAM;

SELECT ID,

TS,

TO_CHAR(TO_DATE(TS, 'YYYY/MM/DD') - 4, 'YYYY/MM/DD') A,

LAG(TS, 4) OVER(PARTITION BY ID ORDER BY TS) B

FROM EXAM;--查询其向上偏移4天的登录时间

SELECT DISTINCT ID

FROM (SELECT ID,

TS, --本次(当天)登录日期

TO_CHAR(TO_DATE(TS, 'YYYY/MM/DD') - 4, 'YYYY/MM/DD') A, --当前数四天的日期

LAG(TS, 4) OVER(PARTITION BY ID ORDER BY TS) B  --上四次的登录日期

FROM EXAM) WHERE B IS NOT NULL;  --ERROR(不能用非空来算)

SELECT DISTINCT ID

FROM (SELECT ID,

TS, --本次(当天)登录日期

TO_CHAR(TO_DATE(TS, 'YYYY/MM/DD') - 4, 'YYYY/MM/DD') A, --当前数四天的日期

LAG(TS, 4) OVER(PARTITION BY ID ORDER BY TS) B  --上四次的登录日期

FROM EXAM) WHERE A=B;

偏移类开窗函数注意点:

1)分析函数名内必须包含要分析的内容,其他两项参数可以默认

2)分析子句内必须添加ORDER BY,且不能指定窗口

3)若不再有可供偏移的行,则返回默认值

4)偏移量不允许写负数

5)分析的字段与默认返回值数据类型要保持一致

2.3开窗函数相关总结

一、各种窗口范围:

PRECEDING:之前的 FOLLOWING:之后的 CURRENT:当前的 UNBOUNDED:不受限的 ROW:行

1.--ROWS BETWEEN N PRECEDING AND N FOLLOWING    前N位到后N位

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN 3 PRECEDING AND 2 FOLLOWING) B

FROM BUSINESS;

2.--ROWS BETWEEN CURRENT ROW AND N FOLLOWING   当前位和到后N位

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING) B

FROM BUSINESS;

3.--ROWS BETWEEN N PRECEDING AND CURRENT ROW  前N位到当前位

SELECT DATE_DT,AMT,SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM BUSINESS;

4.--ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 从前面所有行到当前行

SELECT DATE_DT,AMT,SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM BUSINESS;

5.--ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING  从当前行到后面所有行

SELECT DATE_DT,AMT,SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) FROM BUSINESS;

6.--ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING  全部,

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

FROM BUSINESS;

7.--ROWS BETWEEN UNBOUNDED PRECEDING AND N FOLLOWING  从前面所有到当前行

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

FROM BUSINESS;

8.--ROWS BETWEEN N PRECEDING AND UNBOUNDED FOLLOWING  从前面N行到后面所有

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING)

FROM BUSINESS;

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN 3 PRECEDING AND 2 FOLLOWING) B

FROM BUSINESS; --求的是当前一行前面三个,加上它后面两个的和;  当前的和为六个数相加所得

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) B

FROM BUSINESS;--B的值为B所对应的值加上它前面1位的值和后面1位的值

SELECT DATE_DT,

AMT,

SUM(AMT) OVER(PARTITION BY WEEK ORDER BY DATE_DT ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) B

FROM BUSINESS;

二、不同分析子句组合:--ROWS的出现,必须要伴随ORDER BY

1.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER() FROM EMP ;

2.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(PARTITION BY DEPTNO) FROM EMP ;

3.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(ORDER BY SAL ) FROM EMP ;

4.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM EMP ; --ERROR(窗口字句不能单独出现)

5.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(PARTITION BY DEPTNO ORDER BY SAL) FROM EMP ;

6.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(PARTITION BY DEPTNO ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM EMP ; --ERROR (出现ROWS,必须跟随ORDER BY)

7.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(ORDER BY SAL ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM EMP ;

8.SELECT ENAME,SAL,DEPTNO,SUM(SAL)OVER(PARTITION BY DEPTNO ORDER BY SAL ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM EMP ;

--总结

1.窗口子句不能单独出现,必须要有排序子句出现的情况下才能指定窗口范围

2.若出现排序子句,同时未指定窗口范围,默认的窗口范围是第一行到当前行;若未出现排序子句,

同时未指定窗口范围,默认的窗口范围是第一行到最后一行

3.PARTITION BY 分组的范围

ROWS 统计分析的范围

分析范围不会超过分组范围

三、聚合函数与开窗函数的差异:

1.聚合函数每组数据返回一行值;开窗函数每条数据返回一行值

2.开窗函数后会跟一个OVER(),聚合函数后没有

3.开窗函数通过PARTITION BY 分组 ,聚合函数通过GROUP BY 分组o

4.开窗函数做分析时,并不一定是拿整个分组的数据进行分析,而是通过窗口指定;

聚合函数做分析时,一定是拿整个分组的数据进行分析

ORACLE数据库 开窗函数相关推荐

  1. oracle 数据库 字符串函数

    oracle 数据库 字符串函数 介绍oracle对字符串的操作函数,如图所示,测试字段为:STUDENT 表的 STUNAME 字段 ps:oracle字符串索引从1开始 1.定位索引函数:inst ...

  2. oracle数据库 日期函数用法

    oracle数据库 日期函数用法 –Oracle trunc()函数的用法 /日期******/ 1.select trunc(sysdate) from dual --2013-01-06 今天的日 ...

  3. Oracle数据库常用函数总结

    我本楚狂人,凤歌笑孔丘 ------唐·李白<庐山谣寄卢侍御虚舟> Oracle数据库常用函数总结 一.字符串函数 二.数值函数 三.时间函数 一.字符串函数 显示员工姓名,其中首字母大写 ...

  4. Oracle数据库DECODE函数的使用.

    decode函数是Oracle数据库独有的. 语法为: decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 例子:select decode(sign(变量1-变量2) ...

  5. oracle分析函数-开窗函数

    oracle分析函数 分析函数是什么? 分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计值. ...

  6. Oracle数据库wm_concat()函数的使用方法

    oracle数据库中wm_concat(column)函数使我们经常会使用到的,下面就教您如何使用oracle数据库wm_concat(column)函数实现字段合并 如: shopping: --- ...

  7. oracle数据库函数mod,oracle数据库常用函数

    1.看当前数据库的名字 select name from v$database 2.查看当前数据库实例名 select instance_name from v$instance show param ...

  8. oracle数据库数值函数,五、oracle数据库常用函数

    查看当前数据库的名字 select name from v$database 2.查看当前数据库实例名 select instance_name from v$instance show parame ...

  9. oracle数据库常用函数

    1.单行函数 大小写处理函数如下: LOWER(column|expression)    转换字符值为小写 UPPER(column|expression)    转换字符值为大写 INITCAP( ...

最新文章

  1. 无需额外数据,首次实现ImageNet 87.1% 精度,颜水成团队开源VOLO
  2. conda command not found ubuntu
  3. UESTC_秋实大哥与花 2015 UESTC Training for Data StructuresProblem B
  4. FreeRTOS时间管理
  5. 二十二、PHP框架Laravel学习笔记——集合的使用
  6. 金叉成功率_一个非常强烈的买卖信号:三金叉见顶,三死叉见底,短短10字,但是成功率却远超“金叉买,死叉卖”...
  7. esri-leaflet入门教程(5)- 动态绘制图形
  8. 微信小程序如何上传图片
  9. 我就是为了小米刷机工具写的
  10. android 获取快捷开关_Android11新功能汇总,悬浮聊天气泡、快捷开关颜色可调整等...
  11. ORA-30926: unable to get a stable set of rows in the source tables
  12. 【第三方互联】1、注册成为腾讯QQ开发者
  13. C语言strtok()函数:字符串分割
  14. python (win32com) 批量删除 word (docx, doc) 中所有页眉、页脚 (Word.Application, Word.Basic)
  15. 计算机文字转表格,Word怎么把文字转换成表格 30秒搞定
  16. 20220728使用电脑上的蓝牙和汇承科技的蓝牙模块HC-05配对蓝牙串口传输
  17. win7打开仅计算机黑屏,黑屏只剩鼠标指针,详解win7打开电脑黑屏只剩鼠标指针的解决教程...
  18. CSDN每日打卡已经2周,进展如何?(送两个CSDN背包)
  19. UVA 707 - Robbery
  20. YAMAHA机器人跟上位机TCP通讯

热门文章

  1. 欲穷千里目 更上一层楼!
  2. Javascript ES6中数组去重最简便的两种方法(大概)
  3. Springboot毕业设计毕设作品,动漫网站和AI人物转动漫系统
  4. 抖音跳转微信小程序方法有哪些
  5. 修改注册表解决Win10 SSD卡顿
  6. 重启php软重启_重启PHP命令
  7. vue valley_独立农场游戏Stardew Valley今日在iOS上大获成功
  8. 御数坊:企业级主数据管理平台业务架构及搭建价值探讨 | 会员专栏
  9. 【JS高级】js之闭包对象_04
  10. DELL R740服务器配置RAID 5+1 磁盘阵列