【赵渝强老师】Oracle查询结果集的行号 ROWNUM 详解

简介: 本文详解Oracle ROWNUM伪列原理与实战:强调其动态分配、WHERE前生成、不支持>1等特性;对比ROW_NUMBER()窗口函数及12c+ FETCH分页新语法;涵盖TopN、分页、常见坑点与限制,附视频与代码示例。(239字)

副本_副本_副本_副本_副本_副本_副本_副本_副本_副本_副本_副本_副本_Oracle-课程封面__2026-10-13+11_21_36.png

一、核心定义

ROWNUM 是伪列(不是真实表字段),对查询结果集的行动态分配序号,从1开始。执行顺序关键点:

  1. 读取一行
  2. 应用 WHERE 过滤条件
  3. 如果满足条件 → 分配 ROWNUM,ROWNUM+1
  4. 如果不满足 → 丢弃该行,ROWNUM 不增加
  5. ROWNUM 在 ORDER BY 排序之前生成!


视频讲解如下:


二、基础示例

-- ✅ 取前5条
SQL> SELECT e.*, ROWNUM FROM emp e WHERE ROWNUM <= 5;

# 输出的信息如下:
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO     ROWNUM
----- ---------- --------- ---------- --------- ----- ----- ------ ----------
 7369 SMITH  CLERK     7902 17-DEC-80   800   20      1
 7499 ALLEN  SALESMAN  7698 20-FEB-81  1600 300 30      2
 7521 WARD   SALESMAN  7698 22-FEB-81  1250 500 30      3
 7566 JONES  MANAGER   7839 02-APR-81  2975   20      4
 7654 MARTIN   SALESMAN  7698 28-SEP-81  1250  1400 30      5
 
-- ✅ 只取第1条
SQL> SELECT * FROM emp WHERE ROWNUM = 1;

# 输出的信息如下:
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO
----- ---------- --------- ---------- --------- ----- ----- ------
 7369 SMITH  CLERK     7902 17-DEC-80   800   20
 
-- ❌ 永远返回空!
SQL> SELECT * FROM emp WHERE ROWNUM > 1;
no rows selected

为什么 ROWNUM>1 无数据:

第一条数据拿到,ROWNUM=1,判断 1>1 不成立,丢弃;

下一行依旧尝试分配 ROWNUM=1,永远不会出现 ROWNUM=2。

同理 ROWNUM = 2、ROWNUM >=2 直接查不到数据。


三、高频踩坑:排序后取TopN

-- ❌ 错误!先分配ROWNUM,再排序,不是排序后的前5行
SQL> SELECT * FROM emp WHERE ROWNUM <=5 ORDER BY sal DESC;

# 输出的信息如下:
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO
----- ---------- --------- ---------- --------- ----- ----- ------
 7566 JONES  MANAGER   7839 02-APR-81  2975   20
 7499 ALLEN  SALESMAN  7698 20-FEB-81  1600 300 30
 7654 MARTIN SALESMAN  7698 28-SEP-81  1250  1400 30
 7521 WARD   SALESMAN  7698 22-FEB-81  1250 500 30
 7369 SMITH  CLERK     7902 17-DEC-80   800   20
 
-- ✅ 正确写法:内层先排序,外层再生成ROWNUM
SQL> SELECT * FROM (
         SELECT * FROM emp ORDER BY sal DESC
     ) WHERE ROWNUM <= 5;
     
# 输出的信息如下:
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO
----- ---------- --------- ---------- --------- ----- ----- ------
 7839 KING   PRESIDENT        17-NOV-81  5000   10
 7788 SCOTT  ANALYST   7566 19-APR-87  3000   20
 7902 FORD   ANALYST   7566 03-DEC-81  3000   20
 7566 JONES  MANAGER   7839 02-APR-81  2975   20
 7698 BLAKE  MANAGER   7839 01-MAY-81  2850   30

四、经典分页(Oracle 11g及更早最常用双层子查询分页)

需求:查询第6~10条数据

SQL> SELECT * FROM (
         SELECT t.*, ROWNUM rn
         FROM (
             SELECT * FROM emp ORDER BY sal DESC
         ) t
     ) WHERE rn >= 6 AND rn <= 10;
     
# 输出的信息如下:
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO     RN
----- ---------- --------- ---------- --------- ----- ----- ------ ----------
 7782 CLARK  MANAGER   7839 09-JUN-81  2450   10      6
 7499 ALLEN  SALESMAN  7698 20-FEB-81  1600 300 30      7
 7844 TURNER SALESMAN  7698 08-SEP-81  1500   0 30      8
 7934 MILLER CLERK     7782 23-JAN-82  1300   10      9
 7521 WARD   SALESMAN  7698 22-FEB-81  1250 500 30     10

执行流程:

  1. 最内层:业务排序 ORDER BY
  2. 中层:给排序好的结果生成行号别名 rn
  3. 外层:根据别名 rn 截取分页范围

⚠️ 注意:别名 rn 不能写在中层的WHERE里,因为ROWNUM还没生成完成。

五、窗口函数 ROW_NUMBER()(10g及以上支持)

ROW_NUMBER() 是分析函数,先排序,再生成行号,支持分组编号 PARTITION BY

SQL> SELECT
          t.*,
          ROW_NUMBER() OVER(ORDER BY sal DESC) rn
      FROM emp t;
      
# 输出的信息如下:
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO     RN
----- ---------- --------- ---------- --------- ----- ----- ------ ----------
 7839 KING   PRESIDENT        17-NOV-81  5000   10      1
 7902 FORD   ANALYST   7566 03-DEC-81  3000   20      2
 7788 SCOTT  ANALYST   7566 19-APR-87  3000   20      3
 7566 JONES  MANAGER   7839 02-APR-81  2975   20      4
 7698 BLAKE  MANAGER   7839 01-MAY-81  2850   30      5
 7782 CLARK  MANAGER   7839 09-JUN-81  2450   10      6
 7499 ALLEN  SALESMAN  7698 20-FEB-81  1600 300 30      7
 7844 TURNER SALESMAN  7698 08-SEP-81  1500   0 30      8
 7934 MILLER CLERK     7782 23-JAN-82  1300   10      9
 7521 WARD   SALESMAN  7698 22-FEB-81  1250 500 30     10
 7654 MARTIN SALESMAN  7698 28-SEP-81  1250  1400 30     11
 7876 ADAMS  CLERK     7788 23-MAY-87  1100   20     12
 7900 JAMES  CLERK     7698 03-DEC-81   950   30     13
 7369 SMITH  CLERK     7902 17-DEC-80   800   20     14
14 rows selected.

分页写法:

SQL> SELECT * FROM (
          SELECT
              t.*,
              ROW_NUMBER() OVER(ORDER BY sal DESC) rn
          FROM emp t
      ) WHERE rn BETWEEN 6 AND 10;
      
# 输出的信息如下:      
EMPNO ENAME  JOB      MGR HIREDATE    SAL  COMM DEPTNO     RN
----- ---------- --------- ---------- --------- ----- ----- ------ ----------
 7782 CLARK  MANAGER   7839 09-JUN-81  2450   10      6
 7499 ALLEN  SALESMAN  7698 20-FEB-81  1600 300 30      7
 7844 TURNER SALESMAN  7698 08-SEP-81  1500   0 30      8
 7934 MILLER CLERK     7782 23-JAN-82  1300   10      9
 7521 WARD   SALESMAN  7698 22-FEB-81  1250 500 30     10

六、Oracle12cR1+ 简化分页 FETCH / OFFSET

-- 取前5行
SELECT * FROM emp ORDER BY sal DESC FETCH FIRST 5 ROW ONLY;

-- 跳过10行,取10行(OFFSET从0开始)
SELECT * FROM emp ORDER BY sal DESC OFFSET 10 ROW FETCH NEXT 10 ROW ONLY;

七、ROWNUM 的重要限制

  1. 不能加表别名:t.ROWNUM 语法报错,只能直接写 ROWNUM
  2. ROWNUM 在 WHERE 阶段生成,ORDER BY 在WHERE之后,所以ROWNUM不受排序影响
  3. 遇到 GROUP BY、DISTINCT:先分组/去重,再分配ROWNUM
  4. 多表关联:ROWNUM是最终合并结果集的行号,不是单表独立行号
  5. ROWNUM 是动态的,同一条数据两次查询,ROWNUM可能不一样(无排序时)


相关文章
|
18天前
|
Oracle 关系型数据库 MySQL
【赵渝强老师】国产崖山数据库的行号:ROWNUM
YashanDB的ROWNUM伪列行为类似Oracle,仅支持单机/主备及共享集群,分布式集群不可用。其按查询顺序动态分配行号(1起递增),且“先编号后过滤”,故ROWNUM&gt;1等条件恒为空。推荐使用ROW_NUMBER()窗口函数或原生FETCH/OFFSET语法实现稳定分页。
165 0
|
20天前
|
人工智能 运维 小程序
1人搞定17家企业年做200万:不裸辞先接单的“AI落地商人“
本文是「OPC一人公司通关手册」第33篇,聚焦AI落地新蓝海:当大模型过剩,真正稀缺的是“把AI装进业务”的前线部署工程师(FDE)。98年北京小伙不裸辞、先接单,一人调度4-5个AI智能体,2025年服务17家企业、实现200万业绩——验证了“先有项目、后有公司”的OPC最稳路径。(239字)
|
20天前
|
Web App开发 人工智能 安全
Personal Agent 是什么?为什么大厂都抢着做?连 DeepSeek Bot 都来了。。
Personal Agent 是什么?为什么大厂都在抢着做?跟 OpenClaw、WorkBuddy 等 AI 有什么区别?一文带你搞懂 Muse、Dots 等 Bot,实际体验 Grok Bot,真的好用么?
313 0
Personal Agent 是什么?为什么大厂都抢着做?连 DeepSeek Bot 都来了。。
|
20天前
|
存储 弹性计算 缓存
阿里云服务器2核2G/2核4G/4核8G/8核16G热门配置最新活动价格,38元起,99元与199元续费同价
阿里云热门配置形成从入门到企业级的完整价格带:2核2G轻量应用服务器38元/年起、经济型e实例99元/年,2核4G约199元/年(u1),4核8G通用算力型u2i约1252.63元/年,8核16G、8核32G则面向高并发与数据库场景。同一配置在不同实例家族间价格与技术架构差异明显,峰值带宽不等于固定带宽。选型应结合业务负载、带宽与存储余量、续费政策、账号资格和整体TCO,按需匹配而非只追低价。
|
11月前
|
存储 关系型数据库 数据库
【赵渝强老师】PostgreSQL锁的类型
PostgreSQL通过表级锁和行级锁实现并发控制,结合MVCC机制保障数据一致性。锁模式多样,粒度精细,可有效避免事务冲突,提升并发性能。
457 0
【赵渝强老师】PostgreSQL锁的类型
|
7月前
|
关系型数据库 MySQL Java
【赵渝强老师】MySQL数据库的分库与分表
Mycat是一款开源分布式数据库中间件,支持MySQL等主流数据库,提供分库分表、读写分离、逻辑库/表抽象等功能。本文详解其核心概念(如分片表、ER表、全局序列号)、安装部署(JDK配置、服务启停)及实战配置(schema.xml/rule.xml),并演示基于三节点MySQL的分片数据路由与查询。
436 31
|
7月前
|
网络协议 Java 数据格式
【赵渝强老师】Docker容器的跨节点通信
本文详解Docker容器跨主机通信的三种方案,重点介绍基于Overlay网络的实现:通过ZooKeeper注册中心配置Docker集群,创建overlay网络,使不同主机上的容器能用虚拟IP直接互通,并提供完整部署步骤与验证方法。(239字)
553 3
|
10月前
|
SQL 存储 分布式计算
【赵渝强老师】基于Hudi的大数据湖仓一体架构
Apache Hudi(Hadoop Upserts Delete and Incremental)是开源的流式数据湖平台,支持事务、高效upsert/delete、增量处理、多引擎SQL读写(Spark/Flink/Trino等),自动管理小文件与压缩,兼容云存储,助力构建湖仓一体架构。
1212 3
|
10月前
|
SQL 数据库 OceanBase
【赵渝强老师】OceanBase的配置文件与配置项
OceanBase集群中,OBServer节点需预创建etc、log、run、store等目录,store下还需clog、slog、sstable子目录。etc存放配置文件,etc2/3为自动备份目录,配置项分集群与租户级,通过SHOW PARAMETERS查看,支持模糊查询。
591 4
|
11月前
|
存储 关系型数据库 数据库
【赵渝强老师】国产金仓数据库的体系架构
金仓数据库(KingbaseES)是基于PostgreSQL开发的国产关系型数据库,具有自主知识产权。其体系结构涵盖逻辑存储、物理存储、进程与内存管理,支持高可靠性与性能优化,广泛应用于关键信息基础设施领域。
1446 1