跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

Oracle数据库如何限制查询行数_使用FETCH FIRST或ROWNUM语法

Oracle 12c+优先用FETCH FIRST语法,必须与ORDER BY同级使用,不可嵌套;支持FETCH FIRST N ROWS ONLY、OFFSET M ROWS FETCH NEXT N ROWS ONLY及WITH TIES等用法,缺ORDER BY则结果不确定。 Oracle 12c 及以后版本,优先用
FETCH FIRST
;老版本(如 11g)只能靠
ROWNUM
嵌套子查询,硬绕。 FETCH FIRST 在 Oracle 12c+ 中怎么写才不报错 它必须和
ORDER BY
在同一级 SELECT 中出现,不能丢掉排序,也不能塞进子查询里再加 FETCH。
FETCH FIRST 5 ROWS ONLY
合法,
FETCH FIRST 0 ROWS ONLY
也合法(返回空集),但
FETCH FIRST -1 ROWS ONLY
会直接报
ORA-00933
分页场景写
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
,注意
NEXT
不可省略,
FETCH FIRST 10 ROWS ONLY
和
FETCH NEXT 10 ROWS ONLY
效果一样,但语义上后者更贴合分页上下文 如果漏了
ORDER BY
,语句能执行,但结果不可预测——Oracle 不保证无序时的“前 N 行”是哪几行 性能上,
FETCH
会先完成全量排序再切片,若排序字段没索引,大表可能慢;但执行计划通常比 ROWNUM 嵌套更优,优化器更容易做剪枝 ROWNUM 为什么不能直接写
WHERE ROWNUM > 10
因为
ROWNUM
是动态分配的:Oracle 每生成一行就立刻编号,从 1 开始,且只增不减。所以
ROWNUM > 10
永远不成立——第一行编号是 1,不满足;第二行编号是 2,还是不满足……整条 WHERE 条件始终为假。 想取第 11–20 行,必须两层嵌套:
SELECT * FROM (SELECT a.*, ROWNUM rnum FROM (SELECT * FROM emp ORDER BY salary DESC) a WHERE ROWNUM 10
内层
WHERE ROWNUM 是为了控制上限,避免外层 rnum > 10
时数据已耗尽 中间别名
rnum
是普通列,可以比较;而外层伪列
ROWNUM
无法用于
>
或
=
(除了
=1
) 常见错误:
WHERE ROWNUM BETWEEN 11 AND 20
或
ROWNUM > 10 AND ROWNUM < 20
,全部返回空 ORDER BY 和 ROWNUM 混用时为什么结果不对 根本原因是
ROWNUM
分配发生在排序之前。你写
SELECT * FROM emp WHERE ROWNUM ,Oracle 先随机取 10 行、打上 ROWNUM=1~10,再对这 10 行排序——不是“工资最高的前 10 人”,而是“随便 10 个人里工资排前几的”。
oracle知识库 oracle知识库下载 下载 正确做法永远是子查询先
ORDER BY
,外层再用
ROWNUM
截断:
SELECT * FROM (SELECT * FROM emp ORDER BY salary DESC) WHERE ROWNUM
外层不能再加
ORDER BY
,否则可能破坏
ROWNUM
的逻辑顺序(尤其在并行查询或复杂视图中) 如果原表数据量大、排序字段无索引,这种嵌套会导致全表扫描 + 大排序,内存/临时表空间压力明显高于
FETCH
什么时候必须用 ROWNUM 而不能用 FETCH 只有两种情况:Oracle 版本低于 12c,或者你正在写兼容多版本的脚本且无法判断目标库版本。
FETCH
在 11g 及更早版本会直接报
ORA-00933
,没有任何回退机制 某些旧系统 DBA 禁用了 12c+ 新语法,或应用框架 SQL 解析器不识别
FETCH
关键字 注意:即使版本支持,
FETCH
也不支持“按部门分别取前 3 名”这类需求——这时得用
DENSE_RANK()
或
ROW_NUMBER()
等分析函数,
ROWNUM
同样不行 真正容易被忽略的是执行计划差异:
ROWNUM
嵌套看起来只是多一层括号,但 Oracle 实际执行时很可能物化中间结果集;而
FETCH
更倾向流式处理+提前终止,尤其在有合适索引时。调优时别只看 SQL 写法,一定看
EXPLAIN PLAN
里的
VIEW
和
WINDOW SORT
节点。

相关文章