有没有办法让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
将返回按名称排序的十行的随机集合,这通常不是我想要的。它也不允许指定偏移量。
答案 0 :(得分:751)
您可以使用子查询,如
select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;
还可以查看Oracle / AskTom上的主题On ROWNUM and limiting results以获取更多信息。
<强>更新强>: 为了限制下限和上限的结果,使用
会让事情变得更加臃肿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;
有关更多示例,请参阅this answer。感谢Krumia的提示。
答案 1 :(得分:452)
从Oracle 12c R1(12.1)开始, 一个row limiting clause。它不使用熟悉的LIMIT
语法,但它可以通过更多选项更好地完成工作。您可以找到full syntax here。
要回答原始问题,请点击此处查询:
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
(对于早期的Oracle版本,请参阅此问题中的其他答案)
以下示例引自linked page,希望防止链接腐烂。
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
th 行有关系,则获取所有绑定的行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.
答案 2 :(得分:173)
我针对以下方法进行了一些性能测试:
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之间的行:
答案 3 :(得分:53)
只有一个嵌套查询的分析解决方案:
SELECT * FROM
(
SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
)
WHERE MyRow BETWEEN 10 AND 20;
Rank()
可以代替Row_Number()
,但如果名称有重复值,则可能会返回比预期更多的记录。
答案 4 :(得分:28)
在Oracle 12c上(参见SQL reference中的行限制条款):
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
答案 5 :(得分:11)
在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&gt; 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博客上的文章中了解有关分页查询的更多信息:
答案 6 :(得分:6)
少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;
答案 7 :(得分:5)
正如我在this article中所述,SQL:2008标准提供了以下语法来限制SQL结果集:
pip3 install Tensorflow
Collecting Tensorflow
ERROR: Could not find a version that satisfies the requirement Tensorflow
(from versions: none)
ERROR: No matching distribution found for Tensorflow
在版本12c之前,要获取Top-N记录,您必须使用派生表和ROWNUM伪列:
SELECT
title
FROM
post
ORDER BY
id DESC
FETCH FIRST 50 ROWS ONLY
答案 8 :(得分:3)
作为accepted answer的扩展,Oracle在内部使用ROW_NUMBER/RANK
函数。 OFFSET FETCH
语法是语法糖。
可以使用 DBMS_UTILITY.EXPAND_SQL_TEXT
过程来观察它:
准备样品:
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 DESC
FETCH FIRST 5 ROWS ONLY;
是常规的:
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
ROW_NUMBER() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rownumber"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rownumber"<=5 ORDER BY "A1"."rowlimit_$_0" DESC;
获取扩展的SQL文本:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
WITH TIES
扩展为RANK
:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS WITH TIES',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
RANK() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rank"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rank"<=5 ORDER BY "A1"."rowlimit_$_0" DESC
和偏移量:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
ROW_NUMBER() OVER ( ORDER BY "A2"."VAL") "rowlimit_$$_rownumber"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rownumber"<=CASE WHEN (4>=0) THEN FLOOR(TO_NUMBER(4))
ELSE 0 END +4 AND "A1"."rowlimit_$$_rownumber">4
ORDER BY "A1"."rowlimit_$_0"
答案 9 :(得分:2)
如果您不在Oracle 12C上,则可以使用如下所示的TOP N查询。
SELECT *
FROM
( SELECT rownum rnum
, a.*
FROM sometable a
ORDER BY name
)
WHERE rnum BETWEEN 10 AND 20;
您甚至可以从with子句中的子句移动它,如下所示
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作为过滤条件。
答案 10 :(得分:2)
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
少于值找出
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID=5
答案 11 :(得分:1)
我开始准备Oracle 1z0-047考试,经过12c验证 在准备它的同时,我遇到了一个名为“FETCH FIRST&#39; 它使您可以根据自己的方便获取行/限制行。 有几种选择
- 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
答案 12 :(得分:0)
对于查询返回的每一行,ROWNUM伪列返回一个数字,该数字指示Oracle从表或连接的行集中选择行的顺序。所选的第一行的ROWNUM为1,第二行的为2,依此类推。
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
我已经在oracle
服务器11.2.0.1.0
中实现了这一点
答案 13 :(得分:-2)
对于SQL-Developer,它仅自动获取前50行。如果向下滚动,它会再获取50行,依此类推!
因此,在使用sql-developer工具的情况下,我们无需定义!
答案 14 :(得分:-3)
在oracle中
SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY;
10
10
9
9
8
选择了5行。
SQL&GT;
答案 15 :(得分:-4)
(未经测试)这样的事情可以完成这项工作
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
还有分析函数等级,您可以使用它来排序。
答案 16 :(得分:-5)
与上述相同,有更正。工作,但绝对不漂亮。
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
老实说,最好使用上述答案。