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