有没有办法让Oracle
查询表现得像包含一个MySQL limit
子句?
在MySQL
,我可以这样做:
select * from sometable order by name limit 20,10
获得第21行到第30行(跳过前20行,给出下一行10).在行之后选择行order by
,因此它实际上按字母顺序从第20个名称开始.
在Oracle
,人们提到的唯一的事情是rownum
伪列,但它之前 进行了评估order by
,这意味着:
select * from sometable where rownum <= 10 order by name
将返回按名称排序的十行的随机集合,这通常不是我想要的.它也不允许指定偏移量.
您可以使用子查询
select * from ( select * from emp order by sal desc ) where ROWNUM <= 5;
还可以查看主题On ROWNUM并在Oracle/AskTom上限制结果以获取更多信息.
更新:为了限制下限和上限的结果,事情会变得更加臃肿
select * from ( select a.*, ROWNUM rnum from () 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的暗示.
从Oracle 12C R1(12.1)开始,那里是一个行限制性条款.它不使用熟悉的LIMIT
语法,但它可以通过更多选项更好地完成工作.您可以在此处找到完整语法.
要回答原始问题,这是查询:
SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
(对于早期的Oracle版本,请参阅此问题中的其他答案)
以下示例引用链接页面,以防止链接腐烂.
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 a.*, ROWNUM rnum from (
select * from (
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秒
选择100,000到100,010之间的行:
AskTom:60秒
分析:100秒
选择9,000,000到9,000,010之间的行:
AskTom:130秒
分析:150秒
只有一个嵌套查询的分析解决方案:
SELECT * FROM ( SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t ) WHERE MyRow BETWEEN 10 AND 20;
Rank()
Row_Number()
如果名称有重复值,则可以替换但可能会返回比预期更多的记录.
在Oracle 12c上(参见SQL参考中的行限制子句):
SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
在Oracle中,带有排序的分页查询非常棘手.
Oracle提供了一个ROWNUM伪列,它返回一个数字,指示数据库从一个表或一组连接视图中选择行的顺序.
ROWNUM是一个伪列,让许多人陷入困境.ROWNUM值不会永久分配给一行(这是一种常见的误解).实际分配ROWNUM值时可能会造成混淆.在通过查询的筛选谓词但在查询聚合或排序之前,将 ROWNUM值分配给行.
更重要的是,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解释
前N个和分页查询
少SELECT语句.此外,性能消耗较少.致记:anibal@upf.br
SELECT * FROM (SELECT t.*, rownum AS rn FROM shhospede t) a WHERE a.rn >= in_first AND a.rn <= in_first;