有没有办法让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
( <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 的暗示。
从 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 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 * from (
select statement, rownum as RN with order by clause
) where a.rn >= MIN_ROW and a.rn <= MAX_ROW
表有 1000 万条记录,排序在未编入索引的日期时间行:
选择前 10 行:
选择 100,000 到 100,010 之间的行:
选择 9,000,000 到 9,000,010 之间的行: