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. 可用于:个人练习、团队培训、面试题库
相关推荐
NCIN EXPE3 小时前
redis 使用
数据库·redis·缓存
MongoDB 数据平台3 小时前
为编码代理引入 MongoDB 代理技能和插件
数据库·mongodb
极客on之路3 小时前
mysql explain type 各个字段解释
数据库·mysql
代码雕刻家3 小时前
MySQL与SQL Server的基本指令
数据库·mysql·sqlserver
lThE ANDE3 小时前
开启mysql的binlog日志
数据库·mysql
yejqvow123 小时前
CSS如何控制placeholder文字的颜色_使用--placeholder伪元素
jvm·数据库·python
oLLI PILO3 小时前
nacos2.3.0 接入pgsql或其他数据库
数据库
m0_743623923 小时前
HTML怎么创建多语言切换器_HTML语言选择下拉结构【指南】
jvm·数据库·python
pele4 小时前
Angular 表单中基于下拉选择动态启用字段必填校验的完整实现
jvm·数据库·python