ORACLE数据库 开窗函数

这篇具有很好参考价值的文章主要介绍了ORACLE数据库 开窗函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 开窗函数

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.开窗函数做分析时,并不一定是拿整个分组的数据进行分析,而是通过窗口指定;

聚合函数做分析时,一定是拿整个分组的数据进行分析文章来源地址https://www.toymoban.com/news/detail-671707.html

到了这里,关于ORACLE数据库 开窗函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL8.0数据库开窗函数

          数据库开窗函数是一种在SQL中使用的函数,它可以用来对结果集中的数据进行分组和排序,以便更好地分析和处理数据。开窗函数与聚合函数不同,它不会将多行数据聚合成一行,而是保留每一行数据,并对其进行分组和排序。 常见的开窗函数包括ROW_NUMBER()、RANK()、

    2024年02月08日
    浏览(64)
  • Python办公自动化 – 自动化文本翻译和Oracle数据库操作

    以下是往期的文章目录,需要可以查看哦。 Python办公自动化 – Excel和Word的操作运用 Python办公自动化 – Python发送电子邮件和Outlook的集成 Python办公自动化 – 对PDF文档和PPT文档的处理 Python办公自动化 – 对Excel文档和数据库的操作运用、设置计划任务 Python办公自动化 – 对

    2024年01月17日
    浏览(74)
  • MySQL数据库基础(三):多表查询,子查询,开窗函数

    表与表之间的关系 在SQL语句中,数据表与数据表之间,如果存在关系,一般一共有3种情况: ① 一对一关系(高级) 比如有A、B两张表,A表中的每一条数据,在B表中有一条唯一的数据与之对应。 用户表user user_id(用户编号) 账号username 密码password 001 admin admin888 002 itheima

    2024年02月12日
    浏览(45)
  • 【服务器】python通过JDBC连接到位于Linux远程服务器上的Oracle数据库

    🌈你好呀!我是 是Yu欸 🌌 2024每日百字篆刻时光,感谢你的陪伴与支持 ~ 🚀 欢迎一起踏上探险之旅,挖掘无限可能,共同成长! 没有找到合适的参考链接,在gpt的协作下一步完成了这份指南。欢迎交流 ~ 在Python项目中,如果你的目标是通过JDBC连接到位于Linux远程服务器上

    2024年04月28日
    浏览(68)
  • Oracle数据库面试题 精选 Oracle 面试题

    1.解释冷备份和热备份的不同点以及各自的优点 冷备份 发生在数据库已经正常关闭的情况下,将关键性文件拷贝到另外位置的一种说法。适用于所有模式的数据库。 优点 1. 是非常快速的备份方法(只需拷贝文件) 2. 容易归档(简单拷贝即可) 3. 容易恢复到某个时间点上(只

    2024年02月05日
    浏览(103)
  • 【Oracle】收集Oracle数据库内存相关的信息

    【声明】文章仅供学习交流,观点代表个人,与任何公司无关。 编辑|SQL和数据库技术(ID:SQLplusDB) Oracle数据库包含多个内存区域,每个区域都包含多个子组件。 Oracle Database Memory Structures 根据具体问题的需要,可以通过如下命令收集Oracle数据库内存相关的信息。 例: 注:SET

    2024年01月21日
    浏览(70)
  • 【Oracle】使用 SQL Developer 连接 Oracle 数据库

    SQL Developer 是 Oracle 官方推出的一款免费的数据库开发工具,它提供了丰富的数据库开发功能,其中包括连接 Oracle 数据库的功能。 在本文中,我们将从多个方面详细阐述如何使用 SQL Developer 连接 Oracle 数据库。 在连接 Oracle 数据库前,需要需要做一些准备工作,包括安装 SQ

    2024年02月06日
    浏览(69)
  • Oracle数据库

    ①层次型数据库 ②网状型数据库 ③关系型数据库(主要介绍) E-R图:属性(椭圆形),实体(矩形),联系(菱形-一对一、一对多、多对多) 注:有的联系也有属性 关系型数据库的设计范式: 第一范式(1NF):属性不可再分,字段保证原子性 第二范式(2NF):在满足1

    2024年02月08日
    浏览(58)
  • Oracle 开发篇+Java通过HiKariCP访问Oracle数据库

    标签:HikariCP、数据库连接池、JDBC连接池、 释义:HikariCP 是一个高性能的 JDBC 连接池组件,号称性能最好的后起之秀,是一个基于BoneCP做了不少的改进和优化的高性能JDBC连接池。 ★ Java代码 ※ 如果您觉得文章写的还不错, 别忘了在文末给作者点个赞哦 ~

    2024年02月13日
    浏览(58)
  • 快速监控 Oracle 数据库

    Oracle 数据库在行业内应用广泛,通常存放的非常重要的数据,监控是必不可少的,本文使用 Cprobe 采集 Oracle 监控数据,极致简单,分享给大家。 安装配置 Oracle 简单起见,我使用 Docker 启动 Oracle,命令如下: 如上命令启动之后,Oracle 的监听端口是 1521,用户名/密码是 syst

    2024年01月20日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包