ROWNUM 在分页查询中是如何工作的?

How ROWNUM works in pagination query?

所以我想 select Oracle 数据库中的一系列行。我需要这样做,因为我在 table 中有数百万行,并且我想将结果分页给用户(如果您知道在客户端执行此操作的另一种方法,我正在使用 JavaFX 如果它很重要但是我不认为通过网络发送所有数据以在客户端对它们进行分页是个好主意。

因此,在阅读此 post 后: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; returns 0 行?

  2. 为什么没有简单的方法来做类似 Select ... FROM ... WHERE rownum BETWEEN lowerBound AND upperBound 的事情?

  3. 如何去除结果值中的 r 列?从那里 SQL exclude a column using SELECT * [except columnA] FROM tableA? 我显然需要创建一个视图或一个临时视图 table,但是考虑我的查询还有其他方法吗?

  4. 是否保证分页正确?我阅读了 this article 部分“使用 ROWNUM 分页”,其中说我应该通过一些独特的东西对值进行排序以获得一致的分页(所以我想按 rownum 排序很好,如果你能确认的话)。这不是违背了使用 FIRST_ROWS(N) 的目的吗?

我希望不要太多,我可以拆分成单独的问题,但我认为将它们折叠起来是相关的,因为它们密切相关。

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

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

您有 4 个问题,所有问题都围绕 ROWNUM 的用法和功能展开。我会一一回答每个问题。

Why (this was my first attempt until I search on SO) Select * From Person Where rownum > 100 and rownum < 110; returns 0 rows ?

Thomas Kyte 关于 ROWNUM 和分页的精彩解释 here

A ROWNUM 值在行通过查询的 谓词阶段 之后但在查询进行任何排序之前分配给行或聚合。此外,ROWNUM 值仅在分配后才递增,这就是为什么以下查询永远不会 return 一行:

select * 
  from t 
 where ROWNUM > 1;

因为第一行的 ROWNUM > 1 不成立,ROWNUM 不会前进到 2。因此,任何 ROWNUM 值都不会大于 1。

Why there is no simple way to do something like Select ... FROM ... WHERE rownum BETWEEN lowerBound AND upperBound ?

是的,有。从 Oracle 12c 开始,您可以使用新的 Top-n Row limiting 功能。 .

例如,下面的查询将 return 在 第四高 第七高薪水 之间的员工按升序排列:

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>

How to get rid of the r column in the resulting values?

而不是select *,在外部查询中列出所需的列名。对于经常使用查询,创建视图是一次简单的 activity。

或者,在 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>

Does it ensure correct pagination?

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

例如,

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 上使用新的行限制功能。

很少有好的例子here

我通常这样写查询:

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