当前位置: 首页 > news >正文

(课堂笔记)Oracle 窗口函数/开窗函数/分析函数

窗口函数(OVER)可在SELECT中实现分组计算而不改变行数,核心包括:

1)排名函数(ROW_NUMBER/RANK/DENSE_RANK)用于TOPN查询;

2)LAG/LEAD获取相邻行数据;

3)FIRST_VALUE取组内首条记录;

4)NTILE数据分桶;

5)聚合开窗(SUM/AVG)实现累计计算。


与聚合函数不同,窗口函数保留原行数,通过PARTITION BY分组、ORDER BY排序。


典型应用包括部门薪资排名、同环比分析、累计求和等,需注意结果需子查询过滤,且必须明确排序规则。


(课堂笔记)窗口函数/开窗函数/分析函数


以下是根据你提供的课堂内容,整理出的《窗口函数(开窗函数/分析函数)完整复习笔记》,结构清晰、便于学生复习和记忆:


📌 一、窗口函数概述

基本语法:

sql

函数() OVER (PARTITION BY 分组字段 ORDER BY 排序字段)

核心特点:

特点说明
✅ 只能写在SELECT后面不能用在 WHERE/HAVING 中
✅ 不改变行数每行返回一个值,不会合并多行
✅ 可分组+排序通过PARTITION BY分组,ORDER BY排序

PARTITION 可以省略


PARTITION by 1 order by 1 等于默认值

📌窗口函数 vs 聚合函数

  • 聚合函数:多行 → 1 行

  • 窗口函数:多行 → 多行(每行带聚合结果)


📌 二、排名函数(取 TOP N)

1. 三种排名函数对比

函数特点并列场景示例
ROW_NUMBER()连续不重复1,2,3,4
RANK()重复有间隔1,1,3,4
DENSE_RANK()重复无间隔1,1,2,3

RANK 排名 DENSE 稠密,密集


RANK() 并列跳号 1,2,2,4

DENSE_RANK() 并列不跳 1,2,2,3

2. 基础语法

sql

ROW_NUMBER() OVER (PARTITION BY 分组字段 ORDER BY 排序字段)

3. 实战示例

✅ 每个部门按薪资排名

sql

SELECT ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS RN, E.* FROM EMP E;
✅ 每个部门薪资前三名

sql

SELECT * FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS RN, E.* FROM EMP E ) WHERE RN <= 3;
✅ 公司薪资第 6 名

sql

SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY SAL DESC) AS RN, E.* FROM EMP E ) WHERE RN = 6;
✅ 每年入职员工月薪前三名

sql

SELECT * FROM ( SELECT ROW_NUMBER() OVER ( PARTITION BY TO_CHAR(HIREDATE,'YYYY') ORDER BY SAL + NVL(COMM,0) DESC ) AS RN, E.* FROM EMP E ) WHERE RN <= 3;

📌 三、LAG / LEAD(取上下行,计算同环比)

1. 语法

sql

LAG(字段, 偏移量, 缺省值) OVER (PARTITION BY 分组 ORDER BY 排序) LEAD(字段, 偏移量, 缺省值) OVER (PARTITION BY 分组 ORDER BY 排序)
函数说明
LAG取上一行(往上偏移)
LEAD取下一行(往下偏移)

✅ 偏移量默认 = 1,缺省值默认 = NULL


空值不会触发缺省值,会保持为空。

函数单词中文含义词性
LAGlag滞后、延迟、落后动词/名词
LEADlead领先、超前、引导动词/名词

2. 实战示例

✅ 与上一个入职员工薪资差

sql

SELECT E.*, ABS(SAL - LAG(SAL, 1, 8888) OVER (ORDER BY HIREDATE)) AS 薪资差 FROM EMP E;
✅ 每个部门中,与下一个入职员工薪资差

sql

SELECT E.*, LEAD(SAL) OVER (PARTITION BY DEPTNO ORDER BY HIREDATE) AS NEXT_SAL FROM EMP E;

📌 四、FIRST_VALUE(取每组第一个值)

1. 语法

sql

FIRST_VALUE(目标字段) OVER (PARTITION BY 分组 ORDER BY 排序)

✅ 取每组排序后的第一条数据的指定字段值

2. 实战示例

✅ 每个部门薪资最高的员工姓名

sql

SELECT DISTINCT FIRST_VALUE(ENAME) OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS 最高薪资员工, DEPTNO FROM EMP;

💡 配合ROW_NUMBER方式(更灵活):

sql

SELECT DEPTNO, ENAME FROM ( SELECT DEPTNO, ENAME, ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS RN FROM EMP ) WHERE RN = 1;

📌 五、NTILE(数据切片 / 分桶)

1. 语法

sql

NTILE(桶数) OVER (PARTITION BY 分组 ORDER BY 排序)

✅ 将数据分成 N 份,每行标记所属桶号(1 ~ N)


NTILE 整体读作:/ˈen.taɪl/(恩-太欧)
(重音在第一个音节 “en” 上)


在专业交流中(如讨论数据分桶),通常直接读 “N-tile”(强调 N 的数字,如 “4-tile” 表示四分位)即可,对方更容易理解。

2. 实战示例

✅ 每个部门薪资分成 3 档(高/中/低),输出高薪员工

sql

SELECT * FROM ( SELECT NTILE(3) OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS NT, E.* FROM EMP E ) WHERE NT = 1;

📌 六、聚合开窗函数(累计 / 占比)

1. 语法

sql

SUM() OVER (PARTITION BY 分组 ORDER BY 排序) AVG() OVER (PARTITION BY 分组 ORDER BY 排序)

✅ 带ORDER BY:累计值(逐行累加)
✅ 不带ORDER BY:全组聚合值(每行相同)


关联阅读推荐

Oracle:为什么 ORDER BY 能让 SUM() 变成累计?

2. 实战示例

✅ 公司累计人力成本(随时间推移)

sql

SELECT E.*, SUM(SAL) OVER (ORDER BY HIREDATE) AS 累计薪资 FROM EMP E;
✅ 每个部门累计人力成本

sql

SELECT E.*, SUM(SAL) OVER (PARTITION BY DEPTNO ORDER BY HIREDATE) AS 部门累计薪资 FROM EMP E;
✅ 员工薪资占部门总薪资比例

sql

SELECT E.*, SAL / SUM(SAL) OVER (PARTITION BY DEPTNO) AS 部门薪资占比 FROM EMP E;
✅ 员工薪资占公司总成本比例

sql

SELECT E.*, SAL / SUM(SAL) OVER () AS 公司薪资占比 FROM EMP E;
✅ 每个部门累计平均薪资

sql

SELECT E.*, AVG(SAL) OVER (PARTITION BY DEPTNO ORDER BY HIREDATE) AS 累计平均薪资 FROM EMP E;

📌 七、窗口范围控制(了解)

sql

SUM(SAL) OVER ( PARTITION BY DEPTNO ORDER BY HIREDATE ROWS BETWEEN 2 PRECEDING AND CURRENT ROW )
关键字含义
PRECEDING之前
FOLLOWING之后
CURRENT ROW当前行

💡 一般笔试/面试较少深入,了解即可。


📌 八、常见面试题

Q1:用过哪些窗口函数?

场景函数
TOP N 排名ROW_NUMBER/RANK/DENSE_RANK
同环比LAG/LEAD
数据切片NTILE
累计金额/占比SUM/AVGOVER

Q2:窗口函数和聚合函数的区别?

对比点聚合函数窗口函数
输出行数多行 → 1 行多行 → 多行
分组方式GROUP BYPARTITION BY
使用位置SELECT / HAVING仅 SELECT
能否累计✅(带 ORDER BY)

Oracle 聚合函数 vs 窗口函数 对比总结(书写顺序与执行顺序示例)


📌 九、课堂练习(自测用)

练习1:每个办公地点薪资前三名

sql

SELECT LOC, ENAME, SAL FROM ( SELECT LOC, ENAME, SAL, ROW_NUMBER() OVER (PARTITION BY LOC ORDER BY SAL DESC) AS RN FROM EMP E JOIN DEPT D ON E.DEPTNO = D.DEPTNO ) WHERE RN <= 3;

练习2:每个岗位上一个入职员工的薪资

sql

SELECT JOB, HIREDATE, SAL, LAG(SAL) OVER (PARTITION BY JOB ORDER BY HIREDATE) AS 上一个薪资 FROM EMP;

练习3:每年薪资最高的员工姓名

sql

SELECT DISTINCT TO_CHAR(HIREDATE,'YYYY') AS YEAR, FIRST_VALUE(ENAME) OVER ( PARTITION BY TO_CHAR(HIREDATE,'YYYY') ORDER BY SAL DESC ) AS ENAME FROM EMP;

📌 十、易错提醒

❌ 错误写法✅ 正确理解
WHERE RN <= 3直接使用别名窗口函数的结果需要子查询
PARTITION BY后加 WHERE分区是分组,不是过滤
忘记 ORDER BY 导致排名不准确排名/累计必须明确排序规则
把 LAG 当 LEAD 用LAG = 向上取,LEAD = 向下取

📊 SQL 窗口函数速查表(一页全)

🔧 基础语法

sql

函数() OVER (PARTITION BY 分组字段 ORDER BY 排序字段)

📌 排名函数(TOP N)

函数效果并列示例
ROW_NUMBER()连续不重复1,2,3,4
RANK()有间隔1,1,3,4
DENSE_RANK()无间隔1,1,2,3

sql

-- 每个部门薪资前三名 SELECT * FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS RN, E.* FROM EMP E ) WHERE RN <= 3;

📌 LAG / LEAD(上下行)

函数说明
LAG(字段,偏移,缺省)取上一行
LEAD(字段,偏移,缺省)取下一行

sql

-- 与上一个入职员工薪资差 SELECT SAL - LAG(SAL) OVER (ORDER BY HIREDATE) FROM EMP;

📌FIRST_VALUE(每组首个)

sql

-- 每个部门薪资最高的员工 SELECT DISTINCT FIRST_VALUE(ENAME) OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) FROM EMP;

📌 NTILE(数据切片)

sql

-- 每个部门薪资分3档,取高薪档 SELECT * FROM ( SELECT NTILE(3) OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS NT, E.* FROM EMP ) WHERE NT = 1;

📌 聚合开窗(累计/占比)

写法效果
SUM() OVER(PARTITION BY 组)每组总和(每行相同)
SUM() OVER(ORDER BY 日期)累计求和
SUM() OVER(PARTITION BY 组 ORDER BY 日期)组内累计

sql

-- 部门薪资占比 SELECT SAL / SUM(SAL) OVER (PARTITION BY DEPTNO) FROM EMP; -- 累计人力成本 SELECT SUM(SAL) OVER (ORDER BY HIREDATE) FROM EMP;

⚡ 执行顺序

text

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY ↑ 窗口函数在这里计算

⚠️ 核心要点

✅ 可以❌ 不可以
写在 SELECT 后用在 WHERE/HAVING
PARTITION BY 分组直接使用别名过滤
每行返回一个值合并多行

🎯 场景速查

需求用什么
排名 / TOP NROW_NUMBER
同环比LAG/LEAD
每组第一名FIRST_VALUE
分档/分桶NTILE
累计求和SUM OVER(ORDER BY)
占比SUM OVER(PARTITION BY)

💡记忆口诀:排名用ROW,上下用LAG,切片NTILE,累计SUM OVER

http://www.jsqmd.com/news/711038/

相关文章:

  • 投票小程序怎么做?支持礼物投票+视频投票,多用户开账号
  • 5个技巧掌握After Effects动画导出:Bodymovin插件完全指南
  • 构建交互式生态系统模拟器:基于OpenGL与遗传算法的实时进化系统
  • Google账号登录无标题-配置文件1
  • 开源红队平台Viper实战指南:从多平台C2到LLM智能体攻防
  • KMS智能激活工具终极指南:如何3分钟免费激活Windows和Office全系列
  • 生产RFID门禁卡制造商找哪家
  • 视频修复终极指南:用Untrunc轻松恢复损坏的MP4文件
  • C语言开发者最后的存算适配窗口:仅剩3类未开源指令集支持,手把手教你用__builtin_cim_call()实现零拷贝向量计算(含华为昇腾CIM SDK v2.3.1实测代码)
  • AI数据代理:企业数据分析的革新与挑战
  • 答辩前知网AI率超标:比话降AI快速处理实测降幅2026
  • 如何在Windows/Mac/Linux上使用QtScrcpy实现Android投屏控制:专业级跨平台解决方案
  • 明日方舟游戏资源完整获取指南:2000+高清素材一站式下载
  • Python海龟绘图之画笔属性
  • 终极指南:3步在电脑上免费玩Switch游戏 - Ryujinx模拟器完全教程
  • Codex写脚本:告别重复编码的智能革命
  • 上传一张图片即时生成一个3D世界,灵光App率先将世界模型搬上移动端
  • 维普 AIGC 率 55% 降到 8%!率零一键帮毕业生过维普 AIGC 检测!
  • 物联网毕设简单的开题报告集合
  • 告别离线分析!用Wireshark+Lua脚本实时解析航天测控PDXP数据包(附插件开发实战)
  • 如何构建企业级文件传输解决方案:SFTPGo实战配置指南
  • Mermaid.js饼图与柱状图:告别数据可视化困扰的3步解决方案
  • NAT+OSPF+DHCP 全网通综合实验
  • 知网AIGC率68%急降:比话降AI 2026实测效果记录
  • 万方 AIGC 率 60% 降到 5%!0ailv 一键帮毕业生过万方 AIGC 检测!
  • LLM时代学术引文验证技术解析与应用
  • 别再死记硬背了!用这5个真实项目案例,彻底搞懂C/C++指针与内存管理
  • 明日方舟游戏素材完整开源资源库:8000+高清美术资源一键获取指南
  • Redis如何记录每一次写操作_开启AOF持久化机制实现命令级追加记录
  • 在Ubuntu 22.04上搞定ROS2 Humble与EtherLab主站:从源码编译到避坑实战