ROWNUM在分页查询中的作用是什么?

11
我想在Oracle数据库中选择一系列行。这是必须的,因为该表中有数百万行数据,我想向用户分页显示结果(如果你知道另一种在客户端上进行此操作的方法,请告诉我。我正在使用JavaFX,但我认为将所有数据发送到客户端以分页不是一个好办法)。
在阅读了这篇文章之后:SQL ROWNUM how to return rows between a specific range,我得到了以下查询语句:
Select * From (Select t.*, rownum r from PERSON t) Where r > 100 and r < 110;
100110只是示例。在应用程序中,我只需请求下限并添加大小为10,000以获取接下来的10,000行。 现在结果中出现了rownum列,我不想看到它。由于我对SQL不是很熟悉,所以这是我的问题: 1.为什么(这是我第一次尝试,直到我在SO上搜索)Select * From Person Where rownum > 100 and rownum < 110;返回0行? 2.为什么没有简单的方法做类似Select ... FROM ... WHERE rownum BETWEEN lowerBound AND upperBound的事情? 3.如何摆脱结果值中的r列?从那里SQL exclude a column using SELECT * [except columnA] FROM tableA? 我需要创建一个视图或临时表,但考虑到我的查询,还有其他方法吗? 4.它是否确保正确的分页?我读过这篇文章中的“使用ROWNUM进行分页”部分,该部分说我应该按某些唯一的东西排序以获得一致的分页(所以我猜按rownum排序是可以的,如果你能确认的话)。这难道不是使用的目的吗? 我希望这不会太多,我可以将其拆分为单独的问题,但我认为将它们折叠在一起是相关的。

请参阅 使用Oracle进行分页 - Vadzim
3个回答

30
You have 4个问题,所有问题都围绕着ROWNUM的使用和功能。我将逐一回答每个问题。
为什么(这是我第一次尝试,直到我在SO上搜索)Select * From Person Where rownum > 100 and rownum < 110; 返回0行?
关于ROWNUM和分页的解释,请参见Thomas Kyte的详细说明here
ROWNUM值在查询的谓词阶段通过后但在查询执行任何排序或聚合之前被分配给行。此外,只有在分配了ROWNUM值后才会递增该值,这就是为什么以下查询永远不会返回行的原因:
select * 
  from t 
 where ROWNUM > 1;

因为 ROWNUM > 1 在第一行不成立,所以 ROWNUM 不会递增到2。因此,没有任何 ROWNUM 值能够大于1。

为什么没有一种简单的方法可以像 Select ... FROM ... WHERE rownum BETWEEN lowerBound AND upperBound 这样做?

是的,有了Oracle 12c及以上版本,您可以使用新的Top-n Row limiting功能。 请看我的答案

例如,以下查询将按升序返回第4高7高工资之间的员工:

SQL> SELECT empno, sal
  2  FROM   emp
  3  ORDER BY sal
  4  OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY;

     EMPNO        SAL
---------- ----------
      7654       1250
      7934       1300
      7844       1500
      7499       1600

SQL>

如何在结果值中去掉r列?
在外部查询中列出所需的列名,而不是使用select *。对于频繁使用的查询,创建视图是一项简单的一次性活动。
或者,在SQL*Plus中您可以使用NOPRINT命令。它将不显示您不想显示的列名。但是,它只能在SQL*Plus中使用。
例如,
COLUMN column_name NOPRINT

例如,
SQL> desc dept
 Name                                      Null?    Type
 ----------------------------------------- -------- ------------
 DEPTNO                                             NUMBER(2)
 DNAME                                              VARCHAR2(14)
 LOC                                                VARCHAR2(13)

SQL> COLUMN dname NOPRINT
SQL> COLUMN LOC NOPRINT
SQL> SELECT * FROM dept;

    DEPTNO
----------
        10
        20
        30
        40

SQL>

它是否确保正确的分页?

是的,如果您正确编写分页查询。

例如,

SELECT val
FROM   (SELECT val, rownum AS rnum
        FROM   (SELECT val
                FROM   t
                ORDER BY val)
        WHERE rownum <= 8)
WHERE  rnum >= 5;

       VAL
----------
         3
         3
         4
         4

4 rows selected.

SQL>

或者,像我上面展示的那样,在12c上使用新的行限制功能。

这里有一些好的例子在这里


1
这是我从SO得到的最好的答案之一...我希望我能点赞两次 :-) - user2336315
仅仅是Oracle12的新特性,不需要我按照唯一属性排序对吗? - user2336315
当您需要排序输出时,始终需要使用order by。如果没有order by,则不能保证排序。新功能的好处是您不需要先进行子查询来进行排序,您可以在同一查询中执行order by并选择一个范围。 - Lalit Kumar B
1
但是如果没有排序,它会返回与“Select * From tableName”相同顺序的行吗?这是我在SQL Developer中运行这两个查询时观察到的行为,但我不确定它是否总是如此。 - user2336315
2
如果没有order by,它就毫无意义了。这只是随机的。请记住,除非您明确提到order by,否则没有默认顺序。select * from table将以随机方式给出行。行从未按顺序存储,因此在检索时它们被随机获取。只有当您提到order by时才能保证顺序。因此,如果没有order by,它只是获取随机行。 - Lalit Kumar B
显示剩余5条评论

6

问题2的答案:在Oracle 12中,您可以使用分页功能。

select owner, object_name, object_id
from t
order by owner, object_name
OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY;

5

我通常会写这样的查询:

select * 
from 
(
    select a.*, rownum as rn  
    from table_name a
    where rownum <= 110
)
where rn > 100 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接