如何在订购后限制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 

说实话,最好使用以上的答案。