有没有办法使一个Oracle查询行为像它包含一个MySQL限制子句?

在MySQL中,我可以这样做:

select * 
from sometable
order by name
limit 20,10

要得到第21行到第30行(跳过前20行,给出接下来的10行)。这些行是按顺序选择的,所以实际上是从第20个名字的字母顺序开始的。

在Oracle中,人们唯一提到的是rownum伪列,但它在order by之前求值,这意味着:

select * 
from sometable
where rownum <= 10
order by name

将返回一个随机的10行按名称排序的集合,这通常不是我想要的。它也不允许指定偏移量。


当前回答

(未经测试)像这样的东西可能会起作用

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

还有一个分析函数秩,你可以用它来排序。

其他回答

我已经开始准备Oracle 1z0-047考试,与12c进行了验证 在准备它的时候,我遇到了一个被称为“FETCH FIRST”的12c增强。 它允许您根据您的方便获取行/限制行。 它有几个可用的选项

- 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

只有一个嵌套查询的解析解:

SELECT * FROM
(
   SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
) 
WHERE MyRow BETWEEN 10 AND 20;

Rank()可以代替Row_Number(),但如果name有重复的值,则可能返回比预期更多的记录。

SQL标准

从版本12c开始,Oracle支持SQL:2008标准,该标准提供了以下语法来限制SQL结果集:

SELECT
    title
FROM
    post
ORDER BY
    id DESC
FETCH FIRST 50 ROWS ONLY

Oracle 11g及更老版本

在版本12c之前,要获取Top-N记录,必须使用派生表和ROWNUM伪列:

SELECT *
FROM (
    SELECT
        title
    FROM
        post
    ORDER BY
        id DESC
)
WHERE ROWNUM <= 50

在Oracle 12c上(参见SQL参考中的行限制子句):

SELECT * 
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

我为以下方法做了一些性能测试:

Asktom

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万条记录,排序在一个未索引的datetime行上:

解释计划对所有三个选择显示相同的值(323168) 但是赢家是AskTom (analytic紧随其后)

选择前10行需要:

AskTom: 28-30秒 分析型:33-37秒 短选择:110-140秒

在100,000和100,010之间选择行:

AskTom: 60秒 分析性:100秒

在9,000,000和9,000,010之间选择行:

AskTom: 130秒 分析型:150秒