9

So I want to select a range of rows in an Oracle DB. I need to do this because I have millions of rows in the table and I want to paginate results to the user (if you know another way to do this on the client side, I'm using JavaFX if it matters but I don't think it's a good idea to send all the datas over the network to paginate them on the client side).

So after reading this post: SQL ROWNUM how to return rows between a specific range, I have the following query:

Select * From (Select t.*, rownum r from PERSON t) Where r > 100 and r < 110;

The 100 and 110 are just example. In the application, I just ask for the lower bound and add a size of 10_000 to fetch the next 10_000 rows.

Now the rownum column appears in the result and I don't want to see it. As I'm not very experienced with SQL, here's my questions:

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

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

  3. How to get rid of the r column in the resulting values? From there SQL exclude a column using SELECT * [except columnA] FROM tableA? I need apparently to create a view or a temporary table, but is there another way considering my query?

  4. Does it ensure correct pagination? I read this article section "Pagination with ROWNUM", that said I should order the values by something unique to get a consistent pagination (so I guess ordering by rownum is fine, if you can confirm). Doesn't it defeat the purpose of using FIRST_ROWS(N)?

I hope it's not too much, I could split into separate questions, but I think it's relevant to have them collapsed as they are closely related.

Lalit Kumar B
  • 43,345
  • 10
  • 82
  • 112
user2336315
  • 14,237
  • 9
  • 37
  • 63
  • See also [Paging with Oracle](https://stackoverflow.com/questions/241622/paging-with-oracle) – Vadzim Apr 24 '18 at 17:56

3 Answers3

30

You have 4 questions, and all revolve around the usage and functionality of ROWNUM. I will answer each question one-by-one.

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

Nice explanation by Thomas Kyte regarding ROWNUM and pagination here.

A ROWNUM value is assigned to a row after it passes the predicate phase of the query but before the query does any sorting or aggregation. Also, a ROWNUM value is incremented only after it is assigned, which is why the following query will never return a row:

select * 
  from t 
 where ROWNUM > 1;

Because ROWNUM > 1 is not true for the first row, ROWNUM does not advance to 2. Hence, no ROWNUM value ever gets to be greater than 1.

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

Yes, there is. From Oracle 12c onwards, you could use the new Top-n Row limiting feature. See my answer here.

For example, the below query would return the employees between 4th highest till 7th highest salaries in ascending order:

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?

Instead of select *, list the required column names in the outer query. For frequently using the query, creating a view is a simple one time activity.

Alternatively, in SQL*Plus you could use the NOPRINT command. It will not display the column name you don't want to display. However, it would only work in SQL*Plus.

For example,

COLUMN column_name NOPRINT

For example,

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?

Yes, if you write the pagination query correctly.

For example,

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>

Or, use the new row limiting feature on 12c as I have shown above.

Few good examples here.

Community
  • 1
  • 1
Lalit Kumar B
  • 43,345
  • 10
  • 82
  • 112
  • 1
    That's one of the best answer I had from SO... I wish I could upvote twice :-) – user2336315 May 19 '15 at 09:38
  • Just the new feature from Oracle12 does not requires me to order by a unique attribute right? – user2336315 May 19 '15 at 12:53
  • Order by is always required when you need a sorted output. Without order by there is no guarantee of ordering. The good thing about new feature is that you don't need a subquery to first sort, you could do the order by and select a range in the same query. – Lalit Kumar B May 19 '15 at 13:17
  • 1
    But without an order it would returns rows in the same order as a `Select * From tableName` ? This is the behavior I observe when running both queries in SQL Developer but I'm not sure if it's always the case. – user2336315 May 19 '15 at 13:26
  • 2
    It will be meaningless without an order by. It's just random. And remember, there is no default order unless you explicitly mention an order by. `select * from table` will give you rows in a random manner. Rows are never stored in order, hence when you retrieve they are fetched randomly. An order is guaranteed only when you mention order by. So, without order by it is just getting random rows. – Lalit Kumar B May 19 '15 at 13:30
  • Does it require the column in order by to have unique value? Because I am getting repeated data on page 1 and page 2 when I do a pagination using the query mentioned above. – Swapneel Nov 16 '17 at 14:35
  • @Swapneel You mean duplicate rows? – Lalit Kumar B Nov 21 '17 at 07:57
  • @LalitKumarB There are two records in db which have the same value for the column by which we do order by. The first record from the db comes up in page 1 and page 2 and the second record is not seen. – Swapneel Nov 23 '17 at 13:19
  • @Swapneel Probably you are looking for LIMIT in the pagination query. If not, please post your working test case as a new question. – Lalit Kumar B Nov 27 '17 at 05:21
  • yes, there is a problem with the pagination query if the column that is sorted on does not contain unique values. I am still trying to understand why, but you can fix it by moving the first where out of the inner query into the outer where and changing the condition to use rnum as well, i.e. where rnum <= 8 and rnum >= 5 – more urgent jest Oct 15 '19 at 09:34
6

Answer to question 2: In Oracle 12 you can use pagination

select owner, object_name, object_id
from t
order by owner, object_name
OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY;
Rob van Laarhoven
  • 8,063
  • 1
  • 27
  • 48
4

I usually write a query like this:

select * 
from 
(
    select a.*, rownum as rn  
    from table_name a
    where rownum <= 110
)
where rn > 100 
Pavel Zimogorov
  • 1,339
  • 9
  • 23