如何在订购后限制Oracle查询返回的行数?
有没有办法使Oracle查询的行为像它包含MySQL limit条款? 
在MySQL中,我可以这样做:
 select * from sometable order by name limit 20,10 
 得到第21到第30排(跳过前20,给下10)。 这些行是按order byselectorder by ,所以它按字母顺序从第20个名字开始。 
 在Oracle中,人们提到的唯一的东西是rownum伪列,但是在 order by 之前进行评估,这意味着: 
 select * from sometable where rownum <= 10 order by name 
将返回随机设置的10行按名称sorting,这通常不是我想要的。 它也不允许指定偏移量。
 从Oracle 12c R1(12.1)开始,有一个行限制子句 。 它不使用熟悉的LIMIT语法,但可以使用更多选项更好地完成这项工作。 你可以在这里find完整的语法 。 
为了回答原来的问题,这里是查询:
 SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; 
(对于较早的Oracle版本,请参阅此问题中的其他答案)
例子:
下面的例子是从链接页面引用的,希望能够防止链接腐烂。
build立
 CREATE TABLE rownum_order_test ( val NUMBER ); INSERT ALL INTO rownum_order_test SELECT level FROM dual CONNECT BY level <= 10; COMMIT; 
桌子上有什么?
 SELECT val FROM rownum_order_test ORDER BY val; VAL ---------- 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 20 rows selected. 
 获得第N行 
 SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY; VAL ---------- 10 10 9 9 8 5 rows selected. 
 获取第N行,如果第 N行有关系,则获取所有绑定的行 
 SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS WITH TIES; VAL ---------- 10 10 9 9 8 8 6 rows selected. 
 前面x %的行 
 SELECT val FROM rownum_order_test ORDER BY val FETCH FIRST 20 PERCENT ROWS ONLY; VAL ---------- 1 1 2 2 4 rows selected. 
使用偏移量,对分页非常有用
 SELECT val FROM rownum_order_test ORDER BY val OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY; VAL ---------- 3 3 4 4 4 rows selected. 
您可以将偏移量与百分比组合
 SELECT val FROM rownum_order_test ORDER BY val OFFSET 4 ROWS FETCH NEXT 20 PERCENT ROWS ONLY; VAL ---------- 3 3 4 4 4 rows selected. 
你可以像这样使用子查询
 select * from ( select * from emp order by sal desc ) where ROWNUM <= 5; 
还可以看看On ROWNUM主题, 并在Oracle / AskTom中限制结果以获取更多信息。
更新 :为了限制结果的下限和上限,事情会变得更加臃肿
 select * from ( select a.*, ROWNUM rnum from ( <your_query_goes_here, with order by> ) a where ROWNUM <= :MAX_ROW_TO_FETCH ) where rnum >= :MIN_ROW_TO_FETCH; 
(从指定的AskTom文章复制)
更新2 :从Oracle 12c(12.1)开始,有一个可用于限制行或从偏移量开始的语法。
 SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; 
看到这个答案更多的例子。 感谢Krumia的提示。
我为以下方法做了一些性能testing:
Asktom
 select * from ( select a.*, ROWNUM rnum from ( <select statement with order by clause> ) a where rownum <= MAX_ROW ) where rnum >= MIN_ROW 
分析
 select * from ( <select statement with order by clause> ) where myrow between MIN_ROW and MAX_ROW 
短的select
 select * from ( select statement, rownum as RN with order by clause ) where a.rn >= MIN_ROW and a.rn <= MAX_ROW 
结果
表有1000万条logging,sorting在一个没有索引的date时间行上:
- 解释计划对所有三个选项显示相同的值(323168)
- 但胜利者是AskTom(分析以下紧随其后)
select前10行:
- AskTom:28-30秒
- 分析:33-37秒
- 较短的select:110-140秒
select100,000和100,010之间的行:
- AskTom:60秒
- 分析:100秒
select9,000,000和9,000,010之间的行:
- AskTom:130秒
- 分析:150秒
只有一个嵌套查询的分析解决scheme:
 SELECT * FROM ( SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t ) WHERE MyRow BETWEEN 10 AND 20; 
 可以使用Rank()replaceRow_Number()但是如果名称有重复值,则可能会返回比您预期更多的logging。 
在Oracle 12c上(请参阅SQL参考中的行限制子句):
 SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; 
分页查询与订购在Oracle中非常棘手。
Oracle提供了一个ROWNUM伪列,该伪列返回一个数字,指示数据库从一个表或一组联合视图中select行的顺序。
ROWNUM是一个让许多人陷入麻烦的伪列。 ROWNUM值不是永久分配给一行(这是一个常见的误解)。 当ROWNUM值实际分配时可能会引起混淆。 ROWNUM值在查询通过filter谓词但在查询聚合或sorting之前被分配给一行。
而且,ROWNUM值只有在赋值后才会增加。
这就是为什么followin查询没有返回行:
  select * from (select * from some_table order by some_column) where ROWNUM <= 4 and ROWNUM > 1; 
查询结果的第一行不传递ROWNUM> 1谓词,因此ROWNUM不会增加到2.因此,ROWNUM值不会大于1,因此查询不会返回任何行。
正确定义的查询应该如下所示:
 select * from (select *, ROWNUM rnum from (select * from skijump_results order by points) where ROWNUM <= 4) where rnum > 1; 
在我的关于Vertabelo博客的文章中查找更多关于分页查询的信息:
- Oracle ROWNUM解释
- Top-N和分页查询
lessSELECT语句。 另外,性能消耗较less。 致谢:anibal@upf.br
 SELECT * FROM (SELECT t.*, rownum AS rn FROM shhospede t) a WHERE a.rn >= in_first AND a.rn <= in_first; 
如果您不在Oracle 12C上,可以使用下面的TOP N查询。
 SELECT * FROM ( SELECT rownum rnum , a.* FROM sometable a ORDER BY name ) WHERE rnum BETWEEN 10 AND 20; 
你甚至可以用从句中的从句移动如下
 WITH b AS ( SELECT rownum rnum , a.* FROM sometable a ORDER BY name ) SELECT * FROM b WHERE rnum BETWEEN 10 AND 20; 
实际上,我们正在创build一个内联视图,并将rownum重命名为rnum。 您可以在主查询中使用rnum作为过滤条件。
 select * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, FROM EMP ) EMP where ROWID=5 
更大的价值发现
 select * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, FROM EMP ) EMP where ROWID>5 
less于价值发现
 select * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, FROM EMP ) EMP where ROWID=5 
我开始准备甲骨文1z0 – 047考试,对12Cvalidation虽然准备它,我碰到了12C增强,被称为“取得第一”它使您可以获取行/限制行为您的方便。 它有几个选项可用
 - FETCH FIRST n ROWS ONLY - OFFSET n ROWS FETCH NEXT N1 ROWS ONLY // leave the n rows and display next N1 rows - n % rows via FETCH FIRST N PERCENT ROWS ONLY 
例:
 Select * from XYZ a order by a.pqr FETCH FIRST 10 ROWS ONLY 
我在Oracle SQL Developer中使用以下语句来检索前10行,并为我工作:
 SELECT * FROM <table name> WHERE ROWNUM < = 10 ORDER BY <column name>; 
在oracle中
 SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY; 
VAL
  10 10 9 9 8 
5行被选中。
SQL>
(未经testing)这样的事情可能会做这项工作
 WITH base AS ( select * -- get the table from sometable order by name -- in the desired order ), twenty AS ( select * -- get the first 30 rows from base where rownum < 30 order by name -- in the desired order ) select * -- then get rows 21 .. 30 from twenty where rownum > 20 order by name -- in the desired order 
还有分析function的等级,你可以用来sorting。
与上面相同的更正。 作品,但绝对不漂亮。
  WITH base AS ( select * -- get the table from sometable order by name -- in the desired order ), twenty AS ( select * -- get the first 30 rows from base where rownum <= 30 order by name -- in the desired order ) select * -- then get rows 21 .. 30 from twenty where rownum < 20 order by name -- in the desired order 
说实话,最好使用以上的答案。