Oracle 开窗函数 专项练习文档

本练习专为Oracle 开窗函数(分析函数) 设计,覆盖排名、聚合、分区、行范围、序列值 5 大核心场景,包含基础题、进阶题、综合实战题 3 个难度梯度,附完整表数据、题目、答案、结果解析,适合自学、面试备考、技能巩固。

适用人群 :Oracle 开发 / 测试 / 运维、SQL 进阶学习者核心知识点ROW_NUMBER()/RANK()/DENSE_RANK()SUM()/AVG()/COUNT() 开窗、PARTITION BYORDER BYROWS/RANGELAG()/LEAD()NTILE()


一、练习数据表(可直接执行创建)

1. 创建测试表 + 插入数据

执行以下 SQL,生成练习用的 员工销售业绩表(sale_employee)

sql

复制代码
-- 创建员工销售表
CREATE TABLE sale_employee (
    emp_id     NUMBER(5)    PRIMARY KEY,  -- 员工ID
    emp_name   VARCHAR2(20),             -- 员工姓名
    dept_name  VARCHAR2(20),             -- 部门名称
    sale_month VARCHAR2(10),             -- 销售月份
    sale_amt   NUMBER(10,2)               -- 销售金额
);

-- 插入测试数据
INSERT INTO sale_employee VALUES (101, '张三', '销售一部', '2025-01', 50000);
INSERT INTO sale_employee VALUES (102, '李四', '销售一部', '2025-01', 45000);
INSERT INTO sale_employee VALUES (103, '王五', '销售一部', '2025-01', 50000);
INSERT INTO sale_employee VALUES (104, '赵六', '销售二部', '2025-01', 60000);
INSERT INTO sale_employee VALUES (105, '钱七', '销售二部', '2025-01', 55000);
INSERT INTO sale_employee VALUES (106, '孙八', '销售三部', '2025-01', 38000);
INSERT INTO sale_employee VALUES (101, '张三', '销售一部', '2025-02', 52000);
INSERT INTO sale_employee VALUES (102, '李四', '销售一部', '2025-02', 48000);
INSERT INTO sale_employee VALUES (104, '赵六', '销售二部', '2025-02', 62000);
INSERT INTO sale_employee VALUES (106, '孙八', '销售三部', '2025-02', 40000);
COMMIT;

2. 表数据预览

表格

emp_id emp_name dept_name sale_month sale_amt
101 张三 销售一部 2025-01 50000.00
102 李四 销售一部 2025-01 45000.00
103 王五 销售一部 2025-01 50000.00
104 赵六 销售二部 2025-01 60000.00
105 钱七 销售二部 2025-01 55000.00
106 孙八 销售三部 2025-01 38000.00
101 张三 销售一部 2025-02 52000.00
102 李四 销售一部 2025-02 48000.00
104 赵六 销售二部 2025-02 62000.00
106 孙八 销售三部 2025-02 40000.00

二、分难度练习题

基础题(5 道,核心语法入门)

题目 1

查询所有员工 2025-01 月销售数据,按销售金额降序排名 ,展示连续排名(无并列、无跳跃)。考察:ROW_NUMBER()

题目 2

查询所有员工 2025-01 月销售数据,按销售金额降序排名 ,展示并列排名(相同金额名次相同,后续跳跃)。考察:RANK()

题目 3

查询所有员工 2025-01 月销售数据,按销售金额降序排名 ,展示并列排名(相同金额名次相同,后续不跳跃)。考察:DENSE_RANK()

题目 4

部门分区 ,统计每个部门的总销售额、平均销售额 ,每行数据都展示对应部门的聚合值。考察:SUM()/AVG() OVER(PARTITION BY)

题目 5

将所有员工按销售金额平均分成 3 组 ,展示每组数据。考察:NTILE()


进阶题(5 道,分区 + 排序 + 范围)

题目 6

部门 + 月份 双维度分区,查询每个员工在本部门本月的销售排名 (DENSE_RANK)。考察:PARTITION BY 多字段

题目 7

查询 2025-01 月数据,按销售金额升序,计算累计销售额 (逐行累加)。考察:SUM() OVER(ORDER BY ROWS BETWEEN...)

题目 8

查询每个员工的当月销售额上月销售额 ,无上月数据显示 NULL。考察:LAG() 偏移函数

题目 9

查询每个部门销售额最高的 2 名员工 (不考虑并列)。考察:ROW_NUMBER() + 子查询过滤

题目 10

统计每个员工的销售额,与本部门最高销售额、最低销售额 的差值。考察:MAX()/MIN() OVER(PARTITION BY)


综合实战题(3 道,业务场景落地)

题目 11

统计每个部门每月 的:总销售额、环比增长率(本月 - 上月)/ 上月 * 100%,保留 2 位小数。考察:PARTITION BY + LAG() + 四则运算

题目 12

筛选出连续两个月都有销售记录 的员工,展示员工姓名、两个月销售额。考察:LEAD() + 条件过滤

题目 13

查询每个部门内,销售额超过部门平均值 的员工,展示员工信息、个人销售额、部门平均值。考察:AVG() OVER() + 条件过滤


三、完整答案 + 结果解析

基础题答案

题目 1

sql

复制代码
SELECT 
  emp_name, sale_amt,
  ROW_NUMBER() OVER(ORDER BY sale_amt DESC) AS 连续排名
FROM sale_employee WHERE sale_month = '2025-01';

解析:相同金额也会分配不同名次,结果唯一。

题目 2

sql

复制代码
SELECT 
  emp_name, sale_amt,
  RANK() OVER(ORDER BY sale_amt DESC) AS 并列跳跃排名
FROM sale_employee WHERE sale_month = '2025-01';

解析:张三、王五同第 1,李四直接第 4。

题目 3

sql

复制代码
SELECT 
  emp_name, sale_amt,
  DENSE_RANK() OVER(ORDER BY sale_amt DESC) AS 并列连续排名
FROM sale_employee WHERE sale_month = '2025-01';

解析:张三、王五同第 1,李四第 3,无跳跃。

题目 4

sql

复制代码
SELECT 
  emp_name, dept_name, sale_amt,
  SUM(sale_amt) OVER(PARTITION BY dept_name) AS 部门总销售额,
  AVG(sale_amt) OVER(PARTITION BY dept_name) AS 部门平均销售额
FROM sale_employee;

解析:同一部门所有行展示相同的聚合值。

题目 5

sql

复制代码
SELECT 
  emp_name, sale_amt,
  NTILE(3) OVER(ORDER BY sale_amt DESC) AS 分组编号
FROM sale_employee;

解析:数据按排序平均分配到 3 个组。


进阶题答案

题目 6

sql

复制代码
SELECT 
  emp_name, dept_name, sale_month, sale_amt,
  DENSE_RANK() OVER(PARTITION BY dept_name, sale_month ORDER BY sale_amt DESC) AS 部门月度排名
FROM sale_employee;
题目 7

sql

复制代码
SELECT 
  emp_name, sale_amt,
  SUM(sale_amt) OVER(ORDER BY sale_amt ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 累计销售额
FROM sale_employee WHERE sale_month = '2025-01';
题目 8

sql

复制代码
SELECT 
  emp_name, sale_month, sale_amt,
  LAG(sale_amt, 1, NULL) OVER(PARTITION BY emp_id ORDER BY sale_month) AS 上月销售额
FROM sale_employee;
题目 9

sql

复制代码
SELECT * FROM (
  SELECT 
    emp_name, dept_name, sale_amt,
    ROW_NUMBER() OVER(PARTITION BY dept_name ORDER BY sale_amt DESC) AS rn
  FROM sale_employee
) WHERE rn <= 2;
题目 10

sql

复制代码
SELECT 
  emp_name, dept_name, sale_amt,
  MAX(sale_amt) OVER(PARTITION BY dept_name) - sale_amt AS 与最高差值,
  sale_amt - MIN(sale_amt) OVER(PARTITION BY dept_name) AS 与最低差值
FROM sale_employee;

综合实战题答案

题目 11

sql

复制代码
SELECT 
  dept_name, sale_month, 部门月销售额,
  ROUND((部门月销售额 - 上月销售额)/上月销售额 * 100, 2) AS 环比增长率
FROM (
  SELECT 
    dept_name, sale_month,
    SUM(sale_amt) AS 部门月销售额,
    LAG(SUM(sale_amt),1,NULL) OVER(PARTITION BY dept_name ORDER BY sale_month) AS 上月销售额
  FROM sale_employee GROUP BY dept_name, sale_month
);
题目 12

sql

复制代码
SELECT DISTINCT a.emp_name, a.sale_amt AS 一月销售额, b.sale_amt AS 二月销售额
FROM sale_employee a
JOIN sale_employee b ON a.emp_id = b.emp_id 
WHERE a.sale_month = '2025-01' AND b.sale_month = '2025-02';
题目 13

sql

复制代码
SELECT * FROM (
  SELECT 
    emp_name, dept_name, sale_amt,
    AVG(sale_amt) OVER(PARTITION BY dept_name) AS 部门平均值
  FROM sale_employee
) WHERE sale_amt > 部门平均值;

四、知识点总结(必背)

  1. 排名函数
    • ROW_NUMBER():连续不重复
    • RANK():并列 + 跳跃
    • DENSE_RANK():并列 + 连续
  2. 聚合开窗SUM/AVG/COUNT/MAX/MIN() OVER(PARTITION BY 分区字段 ORDER BY 排序)
  3. 偏移函数LAG(列, 偏移步长) 取上一行,LEAD() 取下一行
  4. 分组函数NTILE(n) 平均分成 n 组
  5. 核心语法开窗函数 OVER(分区 排序 行范围)

五、文档使用说明

  1. 直接复制 创建表 SQL 到 Oracle 客户端(PL/SQL Developer/SQL Developer)执行
  2. 按难度顺序做题,先自行编写,再对照答案校验
  3. 可用于:个人练习、团队培训、面试题库
相关推荐
Java面试题总结2 小时前
WAF 误杀了正常请求怎么补数据?CloudFront + Lambda@Edge 双函数架构实战
数据库·架构·edge
weixin_704266052 小时前
Redis集群架构与搭建全攻略
数据库·redis·架构
二进制_博客2 小时前
使用Datax批量将mysql数据导入hive
数据库·hive·mysql
Hvitur3 小时前
软考架构师【第八章】系统质量属性与架构评估
数据库·架构
遇见你...3 小时前
B01 SpringMVC入门
数据库·sql
2601_949816163 小时前
使用python进行PostgreSQL 数据库连接
数据库·python·postgresql
脑子加油站3 小时前
mysql数据库常用命令
数据库
一个天蝎座 白勺 程序猿3 小时前
KingbaseES性能优化实战:从CPU高使用率到高效运行的全路径解析
数据库·性能优化·时序数据库
SuperHeroWu73 小时前
【Neo4j 】图数据库容器化部署(国内源,Linux 详细步骤)
linux·数据库·neo4j