How to use Oracle ORDER BY and ROWNUM correctly?

SqlOracleSql Order-ByRownum

Sql Problem Overview


I am having a hard time converting stored procedures from SQL Server to Oracle to have our product compatible with it.

I have queries which returns the most recent record of some tables, based on a timestamp :

SQL Server:

SELECT TOP 1 *
FROM RACEWAY_INPUT_LABO
ORDER BY t_stamp DESC

=> That will returns me the most recent record

But Oracle:

SELECT *
FROM raceway_input_labo 
WHERE  rownum <= 1
ORDER BY t_stamp DESC

=> That will returns me the oldest record (probably depending on the index), regardless the ORDER BY statement!

I encapsulated the Oracle query this way to match my requirements:

SELECT * 
FROM 
    (SELECT *
     FROM raceway_input_labo 
     ORDER BY t_stamp DESC)
WHERE  rownum <= 1

and it works. But it sounds like a horrible hack to me, especially if I have a lot of records in the involved tables.

What is the best way to achieve this ?

Sql Solutions


Solution 1 - Sql

The where statement gets executed before the order by. So, your desired query is saying "take the first row and then order it by t_stamp desc". And that is not what you intend.

The subquery method is the proper method for doing this in Oracle.

If you want a version that works in both servers, you can use:

select ril.*
from (select ril.*, row_number() over (order by t_stamp desc) as seqnum
      from raceway_input_labo ril
     ) ril
where seqnum = 1

The outer * will return "1" in the last column. You would need to list the columns individually to avoid this.

Solution 2 - Sql

Use ROW_NUMBER() instead. ROWNUM is a pseudocolumn and ROW_NUMBER() is a function. You can read about difference between them and see the difference in output of below queries:

SELECT * FROM (SELECT rownum, deptno, ename
           FROM scott.emp
        ORDER BY deptno
       )
 WHERE rownum <= 3
 /

ROWNUM    DEPTNO    ENAME
---------------------------
 7        10    CLARK
 14       10    MILLER
 9        10    KING


 SELECT * FROM 
 (
  SELECT deptno, ename
       , ROW_NUMBER() OVER (ORDER BY deptno) rno
  FROM scott.emp
 ORDER BY deptno
 )
WHERE rno <= 3
/

DEPTNO    ENAME    RNO
-------------------------
10    CLARK        1
10    MILLER       2
10    KING         3

Solution 3 - Sql

Since Oracle 12c we now have row limiting clauses which do exactly this.

SELECT *
FROM raceway_input_labo 
ORDER BY t_stamp DESC
FETCH FIRST ROW ONLY

Or many alternatives for different scenarios (first n rows, tie handling, etc.).

Solution 4 - Sql

Documented couple of design issues with this in a comment above. Short story, in Oracle, you need to limit the results manually when you have large tables and/or tables with same column names (and you don't want to explicit type them all out and rename them all). Easy solution is to figure out your breakpoint and limit that in your query. Or you could also do this in the inner query if you don't have the conflicting column names constraint. E.g.

WHERE m_api_log.created_date BETWEEN TO_DATE('10/23/2015 05:00', 'MM/DD/YYYY HH24:MI') 
                                 AND TO_DATE('10/30/2015 23:59', 'MM/DD/YYYY HH24:MI')  

will cut down the results substantially. Then you can ORDER BY or even do the outer query to limit rows.

Also, I think TOAD has a feature to limit rows; but, not sure that does limiting within the actual query on Oracle. Not sure.

Solution 5 - Sql

An alternate I would suggest in this use case is to use the MAX(t_stamp) to get the latest row ... e.g.

select t.* from raceway_input_labo t
where t.t_stamp = (select max(t_stamp) from raceway_input_labo) 
limit 1

My coding pattern preference (perhaps) - reliable, generally performs at or better than trying to select the 1st row from a sorted list - also the intent is more explicitly readable.
Hope this helps ...

SQLer

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLarryView Question on Stackoverflow
Solution 1 - SqlGordon LinoffView Answer on Stackoverflow
Solution 2 - SqlArtView Answer on Stackoverflow
Solution 3 - Sqluser3067860View Answer on Stackoverflow
Solution 4 - SqlmaxweberView Answer on Stackoverflow
Solution 5 - SqlSQLerView Answer on Stackoverflow