How do I limit the number of rows returned by an Oracle query after ordering?
有没有办法让它包含在查询的行为样
在
1 2 3 4 | SELECT * FROM sometable ORDER BY name LIMIT 20,10 |
to get to the 30th(二十一行跳过第一个20一10)。这是
在
1 2 3 4 | SELECT * FROM sometable WHERE rownum <= 10 ORDER BY name |
要返回一随机序的一组行的名称,这是通常不会是我想要的。它也不允许在指定的偏移。
您可以使用类似这样的子查询
1 2 3 4 5 6 | SELECT * FROM ( SELECT * FROM emp ORDER BY sal DESC ) WHERE ROWNUM <= 5; |
还可以查看rownum和limiting results在Oracle/asktom上的主题,了解更多信息。
更新:用上界和下界限制结果会让事情变得更加膨胀
1 2 3 4 5 | 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:从Oracle12c(12.1)开始,有一种语法可以限制行或从偏移量开始。
1 2 3 4 | SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; |
有关更多示例,请参阅此答案。感谢克鲁米娅的提示。
从Oracle12cR1(12.1)开始,有一个行限制子句。它不使用熟悉的
要回答原始问题,请回答以下问题:
1 2 3 4 | SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; |
(对于早期的Oracle版本,请参阅本问题中的其他答案)
实例:下面的例子是从链接页面引用的,以防止链接腐烂。
安装程序1 2 3 4 5 6 7 8 9 10 11 | CREATE TABLE rownum_order_test ( val NUMBER ); INSERT ALL INTO rownum_order_test SELECT level FROM dual CONNECT BY level <= 10; COMMIT; |
桌子上有什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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. |
获取第一行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY; VAL ---------- 10 10 9 9 8 5 ROWS selected. |
得到第一行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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. |
行的顶部
1 2 3 4 5 6 7 8 9 10 11 12 13 | SELECT val FROM rownum_order_test ORDER BY val FETCH FIRST 20 PERCENT ROWS ONLY; VAL ---------- 1 1 2 2 4 ROWS selected. |
使用偏移,对于分页非常有用
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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. |
可以将偏移量与百分比相结合
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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. |
我对以下方法进行了一些性能测试:
阿克托姆1 2 3 4 5 | SELECT * FROM ( SELECT a.*, ROWNUM rnum FROM ( <SELECT statement WITH ORDER BY clause> ) a WHERE rownum <= MAX_ROW ) WHERE rnum >= MIN_ROW |
解析
1 2 3 | SELECT * FROM ( <SELECT statement WITH ORDER BY clause> ) WHERE myrow BETWEEN MIN_ROW AND MAX_ROW |
短期替代方案
1 2 3 | SELECT * FROM ( SELECT statement, rownum AS RN WITH ORDER BY clause ) WHERE a.rn >= MIN_ROW AND a.rn <= MAX_ROW |
结果
表有1000万条记录,排序位于未编制索引的日期时间行上:
- 解释计划显示了三个选择的相同值(323168)
- 但胜利者是Asktom(后面紧跟着分析)
选择前10行:
- asktom:28-30秒
- 分析:33-37秒
- 短备选方案:110-140秒
选择100000到100010之间的行:
- asktom:60秒
- 分析:100秒
选择9000000和9000010之间的行:
- asktom:130秒
- 分析:150秒
仅包含一个嵌套查询的分析解决方案:
1 2 3 4 5 | SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER (ORDER BY name) MyRow FROM sometable t ) WHERE MyRow BETWEEN 10 AND 20; |
在Oracle 12c上(请参阅SQL参考中的行限制子句):
1 2 3 4 | SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; |
在Oracle中,带排序的分页查询非常困难。
Oracle提供一个rownum伪列,该列返回一个数字,指示数据库从一个表或一组联接视图中选择行的顺序。
rownum是一个让很多人陷入麻烦的伪列。rownum值不会永久分配给行(这是一个常见的误解)。当实际分配rownum值时,可能会令人困惑。rownum值在传递查询的筛选谓词之后,但在查询聚合或排序之前分配给行。
更重要的是,rownum值只有在分配后才会递增。
这就是以下查询不返回行的原因:
1 2 3 4 5 | SELECT * FROM (SELECT * FROM some_table ORDER BY some_column) WHERE ROWNUM <= 4 AND ROWNUM > 1; |
查询结果的第一行不传递rownum>1谓词,因此rownum不会增加到2。因此,没有rownum值大于1,因此查询不会返回任何行。
正确定义的查询应如下所示:
1 2 3 4 5 6 7 | SELECT * FROM (SELECT *, ROWNUM rnum FROM (SELECT * FROM skijump_results ORDER BY points) WHERE ROWNUM <= 4) WHERE rnum > 1; |
有关分页查询的更多信息,请参阅我在Vertabelo博客上的文章:
- Oracle Rownum解释
- Top-N和分页查询
更少的select语句。而且,性能消耗更少。学分:[email protected]
1 2 3 4 5 6 | SELECT * FROM (SELECT t.*, rownum AS rn FROM shhospede t) a WHERE a.rn >= in_first AND a.rn <= in_first; |
1 2 3 | SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal DESC),* AS ROWID, FROM EMP ) EMP WHERE ROWID=5 |
大于值则发现
1 2 3 | SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal DESC),* AS ROWID, FROM EMP ) EMP WHERE ROWID>5 |
减去价值,找出
1 2 3 | SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal DESC),* AS ROWID, FROM EMP ) EMP WHERE ROWID=5 |
如果您不在Oracle12c上,可以使用下面的TopN查询。
1 2 3 4 5 6 7 8 | SELECT * FROM ( SELECT rownum rnum , a.* FROM sometable a ORDER BY name ) WHERE rnum BETWEEN 10 AND 20; |
您甚至可以将这个从子句移到WITH子句中,如下所示
1 2 3 4 5 6 7 | WITH b AS ( SELECT rownum rnum , a.* FROM sometable a ORDER BY name ) SELECT * FROM b WHERE rnum BETWEEN 10 AND 20; |
实际上,我们正在创建一个内联视图,并将rownum重命名为rnum。您可以在主查询中使用rnum作为筛选条件。
我开始准备Oracle 1Z0-047考试,根据12C验证在为它做准备时,我遇到了一个12C增强,称为"先取"。它允许您根据自己的方便提取行/限制行。它有几个选项
1 2 3 | - 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 |
例子:
1 2 3 | SELECT * FROM XYZ a ORDER BY a.pqr FETCH FIRST 10 ROWS ONLY |
对于查询返回的每一行,rownum伪列返回一个数字,指示Oracle从一个表或一组联接行中选择行的顺序。选定的第一行的rownum为1,第二行的rownum为2,依此类推。
1 2 3 4 5 6 | SELECT * FROM sometable1 so WHERE so.id IN ( SELECT so2.id FROM sometable2 so2 WHERE ROWNUM <=5 ) AND ORDER BY so.somefield AND ROWNUM <= 100 |
我已经在
在甲骨文中
1 | SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY; |
瓦尔
1 2 3 4 5 | 10 10 9 9 8 |
选择了5行。
SQL>
(未经测试)这样的东西可以完成这项工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
还有分析函数秩,可以用来排序。
与上面相同,但有修正。有效,但绝对不漂亮。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
说实话,最好用上面的答案。