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

Oracle数据库数据编程SQL<00. 课外关注:rownum、rowid、level、row_number 对比详解与实战>

更多Oracle学习内容请查看:Oracle保姆级超详细系列教程_Tyler先森的博客-CSDN博客

目录

一、基本概念与区别

二、ROWNUM 详解与实战

1. 基本特性

2. 典型应用

2.1 分页查询(Oracle传统方式)

2.2 限制返回行数

2.3 随机抽样

3. 注意事项

三、ROWID 详解与实战

1. 组成结构

2. 典型应用

2.1 快速定位行

2.2 删除重复记录

2.3 表数据物理分布分析

3. 注意事项

四、LEVEL 详解与实战

1. 基本特性

2. 典型应用

2.1 组织架构查询

2.2 产品分类层次

2.3 路径枚举

3. 注意事项

五、ROW_NUMBER() 详解与实战

1. 基本语法

2. 典型应用

2.1 现代分页查询

2.2 分组排序

2.3 删除重复记录(保留最新)

3. 注意事项

六、对比分析与联合使用

1. 性能比较

2. 联合使用示例

2.1 高效分页组合

2.2 层次查询增强

2.3 物理分布分析

七、实战案例

案例1:员工数据清洗

案例2:产品分类报表

案例3:销售分析

八、常见问题解答


一、基本概念与区别

特性rownumrowidlevelrow_number()
类型伪列伪列伪列分析函数
作用结果集行号行物理地址层次查询级别分组排序行号
唯一性每次查询不同全局唯一同层次相同按分区排序唯一
持久性临时性永久性临时性临时性
修改影响结果集变化即变行物理位置不变则不变查询结构决定结果集变化即变

二、ROWNUM 详解与实战

1. 基本特性

  • 在查询结果返回前分配
  • 从1开始递增
  • 不可直接用于WHERE条件中大于比较

2. 典型应用

2.1 分页查询(Oracle传统方式)

-- 第一页(1-10条)
SELECT * FROM (SELECT a.*, ROWNUM rn FROM employees a WHERE ROWNUM <= 10
) WHERE rn >= 1;-- 第二页(11-20条)
SELECT * FROM (SELECT a.*, ROWNUM rn FROM employees a WHERE ROWNUM <= 20
) WHERE rn >= 11;

2.2 限制返回行数

-- 只返回前5条记录
SELECT * FROM employees WHERE ROWNUM <= 5;

2.3 随机抽样

-- 随机获取10条记录
SELECT * FROM (SELECT * FROM employees ORDER BY DBMS_RANDOM.VALUE
) WHERE ROWNUM <= 10;

3. 注意事项

  • 以下写法无法返回任何结果
    SELECT * FROM employees WHERE ROWNUM > 5;
  • 执行顺序:WHERE条件应用时ROWNUM尚未分配

三、ROWID 详解与实战

1. 组成结构

OOOOOO.FFF.BBBBBB.RRR

  • OOOOOO:数据对象ID
  • FFF:相对文件号
  • BBBBBB:块号
  • RRR:行号

2. 典型应用

2.1 快速定位行

-- 先获取ROWID
SELECT ROWID, employee_id, last_name 
FROM employees 
WHERE employee_id = 100;-- 使用ROWID直接访问(最快访问方式)
SELECT * FROM employees 
WHERE ROWID = 'AAAR5qAAFAAAADMAAA';

2.2 删除重复记录

-- 保留ROWID最小的记录
DELETE FROM employees
WHERE ROWID NOT IN (SELECT MIN(ROWID)FROM employeesGROUP BY employee_id, email  -- 根据业务确定唯一键
);

2.3 表数据物理分布分析

-- 分析数据物理分布
SELECT DBMS_ROWID.ROWID_OBJECT(ROWID) AS object_id,DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) AS file_no,DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) AS block_no,COUNT(*) AS rows_count
FROM employees
GROUP BY DBMS_ROWID.ROWID_OBJECT(ROWID),DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID),DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
ORDER BY rows_count DESC;

3. 注意事项

  • ROWID会随表移动(如exp/imp)而变化
  • 索引组织表(IOT)的ROWID是逻辑的

四、LEVEL 详解与实战

1. 基本特性

  • 专用于层次查询(CONNECT BY)
  • 从1开始(root节点)
  • 表示节点在树中的深度

2. 典型应用

2.1 组织架构查询

-- 查询员工及其所有下属
SELECT LEVEL,LPAD(' ', 2*(LEVEL-1)) || last_name AS org_chart,employee_id,manager_id
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;

2.2 产品分类层次

-- 多级分类查询
SELECT LEVEL,LPAD(' ', 3*(LEVEL-1)) || category_name AS category_tree
FROM product_categories
START WITH parent_id IS NULL
CONNECT BY PRIOR category_id = parent_id;

2.3 路径枚举

-- 显示完整路径
SELECT LEVEL,SYS_CONNECT_BY_PATH(last_name, '/') AS path
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;

3. 注意事项

  • 必须与CONNECT BY子句一起使用
  • 循环引用会导致ORA-01436错误,需加NOCYCLE

五、ROW_NUMBER() 详解与实战

1. 基本语法

ROW_NUMBER() OVER ([PARTITION BY expr1, expr2,...]ORDER BY expr1 [ASC|DESC], expr2 [ASC|DESC],...
)

2. 典型应用

2.1 现代分页查询

-- 更高效的分页(12c以上)
SELECT * FROM (SELECT e.*,ROW_NUMBER() OVER (ORDER BY hire_date) AS rnFROM employees e
)
WHERE rn BETWEEN 11 AND 20;

2.2 分组排序

-- 每个部门薪资前3名
SELECT * FROM (SELECT e.*,ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rankFROM employees e
)
WHERE dept_rank <= 3;

2.3 删除重复记录(保留最新)

-- 保留每组ID最新的记录
DELETE FROM customer_orders
WHERE (order_id, customer_id) IN (SELECT order_id, customer_id FROM (SELECT order_id, customer_id,ROW_NUMBER() OVER (PARTITION BY customer_idORDER BY order_date DESC) AS rnFROM customer_orders)WHERE rn > 1
);

3. 注意事项

  • 是分析函数,不是伪列
  • 相同排序值会获得不同行号(与rank()/dense_rank()不同)

六、对比分析与联合使用

1. 性能比较

  • ROWID访问最快:直接物理定位
  • ROWNUM过滤最早:在结果集返回前应用
  • ROW_NUMBER最灵活:但需要完整排序

2. 联合使用示例

2.1 高效分页组合

SELECT * FROM (SELECT a.*, ROW_NUMBER() OVER (ORDER BY hire_date) AS rn,ROWNUM AS tmp_numFROM employees a
)
WHERE rn BETWEEN 21 AND 30;

2.2 层次查询增强

SELECT LEVEL,ROWID,ROW_NUMBER() OVER (PARTITION BY LEVEL ORDER BY last_name) AS name_rank,last_name
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;

2.3 物理分布分析

SELECT DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) AS block_no,COUNT(*) AS rows_per_block,ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) AS density_rank,ROWNUM AS report_line
FROM employees
GROUP BY DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
HAVING COUNT(*) > 10;

七、实战案例

案例1:员工数据清洗

-- 找出重复邮箱的员工(使用ROW_NUMBER)
SELECT * FROM (SELECT e.*,ROW_NUMBER() OVER (PARTITION BY email ORDER BY employee_id) AS dup_flagFROM employees e
)
WHERE dup_flag > 1;-- 删除重复(保留ID最小的,使用ROWID)
DELETE FROM employees
WHERE ROWID NOT IN (SELECT MIN(ROWID)FROM employeesGROUP BY email
);

案例2:产品分类报表

-- 生成带缩进的分类树(LEVEL)
SELECT LEVEL,LPAD(' ', 4*(LEVEL-1)) || category_name AS category_tree,ROW_NUMBER() OVER (ORDER BY category_path) AS report_line
FROM (SELECT category_id,category_name,parent_id,SYS_CONNECT_BY_PATH(category_name, '/') AS category_pathFROM product_categoriesSTART WITH parent_id IS NULLCONNECT BY PRIOR category_id = parent_id
);

案例3:销售分析

-- 每月销售前三名产品
SELECT * FROM (SELECT product_id,TO_CHAR(sale_date, 'YYYY-MM') AS month,SUM(amount) AS total_sales,ROW_NUMBER() OVER (PARTITION BY TO_CHAR(sale_date, 'YYYY-MM')ORDER BY SUM(amount) DESC) AS sales_rank,ROWNUM AS report_seqFROM salesGROUP BY product_id, TO_CHAR(sale_date, 'YYYY-MM')
)
WHERE sales_rank <= 3
ORDER BY month, sales_rank;

八、常见问题解答

Q1:ROWNUM和ROW_NUMBER()哪个性能更好?

A1:对于简单限制行数,ROWNUM性能更好,因为它不需要排序。对于复杂分组排序,ROW_NUMBER()更合适。

Q2:ROWID会变化吗?

A2:以下情况会变:

  • 表移动(MOVE)

  • 表重建

  • 分区操作

  • 使用EXP/IMP迁移数据

Q3:LEVEL能否用于普通查询?

A3:不能,必须与CONNECT BY层次查询一起使用。

Q4:如何选择分页方法?

A4:

  • Oracle 12c+:使用FETCH FIRST/OFFSET

  • 11g及以下:简单分页用ROWNUM,复杂排序分页用ROW_NUMBER()

Q5:ROW_NUMBER() vs RANK() vs DENSE_RANK()

A5:

  • ROW_NUMBER():连续唯一序号(1,2,3,4)

  • RANK():相同值同序号,跳号(1,2,2,4)

  • DENSE_RANK():相同值同序号,不跳号(1,2,2,3)

更多Oracle学习内容请查看:Oracle保姆级超详细系列教程_Tyler先森的博客-CSDN博客 

相关文章:

  • Mac关闭sip方法
  • MySQL-运维篇
  • OpenCV核心模块中的矩阵操作
  • 10【模块学习】LCD1602(二):6路温度显示+实时时钟
  • pytorch实现逻辑回归
  • 提高RS-485总线稳定性办法
  • 黑马商城项目(一)MybatisPlus
  • 基于PySide6的YOLOv8/11目标检测GUI界面——智能安全帽检测系统
  • ScrollView(滚动视图)详解和按钮点击事件
  • 【Leetcode-Hot100】最小覆盖子串
  • 【链表】链表类型题目常用技巧及例题
  • Resilience4j与Spring Cloud Gateway整合指南:构建弹性的API网关
  • Stable Diffusion 图像生成 GUI 应用:图像缩放等五个优化——SD界面学习记录
  • yml文件上传并映射到实体类
  • Service生命周期
  • 微图4在《宁夏清水湾小流域治理》工程项目中的应用案例
  • Arrays.asList()的对象不能调用add/remove/clear方法
  • 力扣-hot100(最长连续序列 - Hash)
  • C++高级2 智能指针
  • CodeBuddy 焕新升级: 软件开发智能体 Craft 重磅发布
  • 中国戏剧奖梅花奖终评启动在即,17场演出公益票将发售
  • 大学2025丨浙大哲学院院长王俊:文科的价值不在于直接创造GDP
  • 62岁中国国际商会副会长、康力电梯创始人王友林逝世
  • 被指违反代理协议遭南航暂停售票资格, 去哪儿网:今起恢复
  • 深一度|奥运一年后丢冠不稀奇,但究竟谁来扛起男乒的大旗
  • 美国多地举行抗议活动,特朗普经济政策支持率创新低