如何在订购后限制Oracle查询返回的行数?
有没有办法使Oracle查询的行为像它包含MySQL limit
条款?
在MySQL中,我可以这样做:
select * from sometable order by name limit 20,10
得到第21到第30排(跳过前20,给下10)。 这些行是按order by
selectorder 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
说实话,最好使用以上的答案。