如何限制 Oracle 查询排序后返回的行数?
有没有办法让 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
将返回按名称排序的随机十行集,这通常不是我想要的。 它也不允许指定偏移量。
Is there a way to make an Oracle
query behave like it contains a MySQL limit
clause?
In MySQL, I can do this:
select *
from sometable
order by name
limit 20,10
to get the 21st to the 30th rows (skip the first 20, give the next 10). The rows are selected after the order by
, so it really starts on the 20th name alphabetically.
In Oracle, the only thing people mention is the rownum
pseudo-column, but it is evaluated before order by
, which means this:
select *
from sometable
where rownum <= 10
order by name
will return a random set of ten rows ordered by name, which is not usually what I want. It also doesn't allow for specifying an offset.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
您可以为此使用子查询,例如
还可以查看主题 关于 ROWNUM 和限制结果,请访问 Oracle/AskTom 以获取更多信息。
更新:
为了限制结果的下限和上限,事情变得有点臃肿
(从指定的 AskTom 文章复制)
更新 2:
从 Oracle 12c (12.1) 开始,有一种语法可用于限制行或从偏移量开始。
有关更多示例,请参阅此答案。 感谢克鲁米亚的提示。
You can use a subquery for this like
Have also a look at the topic On ROWNUM and limiting results at Oracle/AskTom for more information.
Update:
To limit the result with both lower and upper bounds things get a bit more bloated with
(Copied from specified AskTom-article)
Update 2:
Starting with Oracle 12c (12.1) there is a syntax available to limit rows or start at offsets.
See this answer for more examples. Thanks to Krumia for the hint.
从 Oracle 12c R1 (12.1) 开始,有一个 行限制子句。 它不使用熟悉的
LIMIT
语法,但它可以通过更多选项更好地完成工作。 您可以在此处找到完整语法。 (另请阅读此答案了解有关 Oracle 内部如何工作的更多信息)。为了回答原来的问题,这里是查询:(
对于早期的Oracle版本,请参阅此问题中的其他答案)
示例:
以下示例引用自链接页面,希望防止链接失效。
设置
表中有什么?
获取前
N
行获取前
N
行,如果N
第行有平局,则获取所有平局行
x
% 行使用偏移量,对于分页非常有用
您可以将偏移量与百分比结合起来
Starting from Oracle 12c R1 (12.1), there is a row limiting clause. It does not use familiar
LIMIT
syntax, but it can do the job better with more options. You can find the full syntax here. (Also read more on how this works internally in Oracle in this answer).To answer the original question, here's the query:
(For earlier Oracle versions, please refer to other answers in this question)
Examples:
Following examples were quoted from linked page, in the hope of preventing link rot.
Setup
What's in the table?
Get first
N
rowsGet first
N
rows, ifN
th row has ties, get all the tied rowsTop
x
% of rowsUsing an offset, very useful for pagination
You can combine offset with percentages
我对以下方法进行了一些性能测试:
Asktom
分析
短替代
结果
表有 1000 万条记录,排序在未索引的日期时间行上:
选择前 10 行花费了:
选择 100,000 到 100,010 之间的行:
选择 9,000,000 到 9,000,010 之间的行:
I did some performance testing for the following approaches:
Asktom
Analytical
Short Alternative
Results
Table had 10 million records, sort was on an unindexed datetime row:
Selecting first 10 rows took:
Selecting rows between 100,000 and 100,010:
Selecting rows between 9,000,000 and 9,000,010:
仅包含一个嵌套查询的分析解决方案:
Rank()
可以替代Row_Number()
,但如果名称存在重复值,则返回的记录数可能会超出您的预期。An analytic solution with only one nested query:
Rank()
could be substituted forRow_Number()
but might return more records than you are expecting if there are duplicate values for name.SQL 标准
从版本 12c 开始,Oracle 支持 SQL:2008 标准,该标准提供以下语法来限制 SQL 结果集:
Oracle 11g 及更早版本
在版本 12c 之前,获取 Top-N 条记录,您必须使用派生表和
ROWNUM
伪列:SQL Standard
Since version 12c Oracle supports the SQL:2008 Standard, which provides the following syntax to limit the SQL result set:
Oracle 11g and older versions
Prior to version 12c, to fetch the Top-N records, you had to use a derived table and the
ROWNUM
pseudocolumn:在 Oracle 12c 上(请参阅 SQL 参考中的行限制子句):
On Oracle 12c (see row limiting clause in SQL reference):
在 Oracle 中,带排序的分页查询确实很棘手。
Oracle 提供了一个 ROWNUM 伪列,它返回一个数字,指示数据库从表或联接视图集中选择行的顺序。
ROWNUM 是一个伪列,它给很多人带来了麻烦。 ROWNUM 值不会永久分配给行(这是一个常见的误解)。 当实际分配 ROWNUM 值时可能会令人困惑。 ROWNUM 值在通过查询的过滤谓词之后但在查询聚合或排序之前分配给行。
而且,ROWNUM 值仅在分配后才会递增。
这就是为什么下面的查询不返回任何行的原因:
查询结果的第一行没有通过 ROWNUM > 。 1 谓词,因此 ROWNUM 不会增加到 2。因此,没有 ROWNUM 值大于 1,因此查询不会返回任何行。
正确定义的查询应如下所示:
在我的 Vertabelo 博客上的文章中了解有关分页查询的更多信息:
Pagination queries with ordering are really tricky in Oracle.
Oracle provides a ROWNUM pseudocolumn that returns a number indicating the order in which the database selects the row from a table or set of joined views.
ROWNUM is a pseudocolumn that gets many people into trouble. A ROWNUM value is not permanently assigned to a row (this is a common misunderstanding). It may be confusing when a ROWNUM value is actually assigned. A ROWNUM value is assigned to a row after it passes filter predicates of the query but before query aggregation or sorting.
What is more, a ROWNUM value is incremented only after it is assigned.
This is why the followin query returns no rows:
The first row of the query result does not pass ROWNUM > 1 predicate, so ROWNUM does not increment to 2. For this reason, no ROWNUM value gets greater than 1, consequently, the query returns no rows.
Correctly defined query should look like this:
Find out more about pagination queries in my articles on Vertabelo blog:
作为接受的答案的扩展,Oracle 内部使用
ROW_NUMBER/RANK
函数。OFFSET FETCH
语法是一种语法糖。可以通过使用
DBMS_UTILITY.EXPAND_SQL_TEXT
过程来观察:准备示例:
查询:
是常规的:
db<>fiddle demo
获取扩展的 SQL 文本:
WITH TIES
扩展为RANK< /code>:
和偏移量:
As an extension of accepted answer Oracle internally uses
ROW_NUMBER/RANK
functions.OFFSET FETCH
syntax is a syntax sugar.It could be observed by using
DBMS_UTILITY.EXPAND_SQL_TEXT
procedure:Preparing sample:
Query:
is regular:
db<>fiddle demo
Fetching expanded SQL text:
WITH TIES
is expanded asRANK
:and offset:
使用 21c 版本,您可以简单地应用限制,如下所示:
With 21c version, you can simple apply a limit as follows:
更少的 SELECT 语句。 此外,性能消耗也更少。 致谢:[电子邮件受保护]
Less SELECT statements. Also, less performance consuming. Credits to: [email protected]
我已开始准备 Oracle 1z0-047 考试,并针对 12c 进行了验证
在准备过程中,我遇到了一个名为“FETCH FIRST”的 12c 增强功能
它使您能够根据您的方便获取行/限制行。
它有几个选项可用
示例:
I'v started preparing for Oracle 1z0-047 exam, validated against 12c
While prepping for it i came across a 12c enhancement known as 'FETCH FIRST'
It enables you to fetch rows /limit rows as per your convenience.
Several options are available with it
Example:
对于查询返回的每一行,ROWNUM 伪列返回一个数字,指示 Oracle 从表或连接行集中选择行的顺序。 选择的第一行的 ROWNUM 为 1,第二行的 ROWNUM 为 2,依此类推。
我已在
oracle
服务器11.2.0.1.0
中实现了此功能For each row returned by a query, the ROWNUM pseudocolumn returns a number indicating the order in which Oracle selects the row from a table or set of joined rows. The first row selected has a ROWNUM of 1, the second has 2, and so on.
I have implemented this in
oracle
server11.2.0.1.0
您还可以使用以下查询,
在这种情况下,您可以跳过前
x
行并将结果限制为接下来的y
行。然后您可以使用
x
和y
来对数据进行分页。you can also use following query
in this case you can skip first
x
rows and limit resault into nexty
rows.then you can play around with
x
andy
inorder to paginate over your data.大于值发现
小于值发现
greater then values find out
less then values find out
如果分页中使用的 orderby 列有重复值。 我们可以首先 order by 生成特定的排序,然后限制情况
If the orderby column used in pagination has duplicate values. We can first order by to generate a particular ordering and then limit the case
(未经测试)类似的东西可以完成这项工作
还有分析函数排名,您可以使用它来排序。
(untested) something like this may do the job
There is also the analytic function rank, that you can use to order by.