tags:

views:

660

answers:

4

Im using an Oracle database.

In my query 100 rows are fetched. If I want to filter rows between rownum 50 and 60, what would be the query?

SELECT EMPLID, EFFDT, ACTION, ACTION_REASON 
from JOB where emplid ='12345'
+5  A: 

It's a little tricky in Oracle, I think you have to do something like this:

SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
FROM (SELECT ROWNUM rnum, EMPLID,EFFDT,ACTION,ACTION_REASON
      FROM (SELECT EMPLID,EFFDT,ACTION,ACTION_REASON
            FROM JOB
            WHERE emplid = '12345')
      WHERE rownum <= 60
)
WHERE rnum >= 50;
Chad Birch
Is rownum ORDER BY sensitive?
Tomalak
No, it's calculated only when the row is already fetched.
Quassnoi
I believe so http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/pseudocolumns009.htm#SQLRF00255
Dana the Sane
Yeah, so an ORDER BY in the innermost query would be a very good idea, he just didn't have one in his example so I didn't want to guess at the right ordering.
Chad Birch
I thank you all for your prompt response. I really appreciate your help.
Bobby, can you mark one of these as the answer that you used?
Nick
Ive used the query provided by Nick.
@Bobby: By "mark", Nick meant "check as the accepted answer". ;-)
Tomalak
@Tomalak, Thanks for the clarification.
Nick
A: 

You can use ROWNUM (see this link). If you need to control sort order, you can wrap another query around your query.

cdonner
I thank you all for your prompt response. I really appreciate your help.
+7  A: 

Most people will commonly tell you to use ROWNUM, to do this, however the more succinct way is the use the row_number() analytic function.

select EMPLID, EFFDT, ACTION, ACTION_REASON
from
(
SELECT EMPLID, EFFDT, ACTION, ACTION_REASON, row_number() over (order by emplid) rn
from JOB where emplid ='12345'
)
where rn between 50 and 60;

Using the row_number function allows you to order the results AND number them in a single query, then you just need one wrapper query to get the rows you need.

Nick
Thanks Nick, it worked. I really appreciate your help.
Not true: just because it LOOKS like a query within a query within a query, it doesn't mean Oracle implements it like that. I just tested each method 10,000 times and they ran in 69 and 78 ms (yours was the slower as it happens, but the difference is insignificant). Explain Plan shows what happens
Tony Andrews
On my system the times are insignificant both run in the 1.5 ms range on my table, however the row_number's syntax is cleaner and doesn't require two inline views. See Tom Kyte, http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html
Nick
Agreed - it was the assertion that yours was "the more efficient" way that I was calling you on! They are to all intents and purposes equally efficient.
Tony Andrews
In fact, if you remove the "more efficient" claim from your answer, I'll vote it up!
Tony Andrews
I would expect that the rownum method is potentially more efficient, as the optimizer is more likely to recognise that an index-based access method to return the ordered rows would be more efficient than getting all the rows and calculating a ROW_NUMBER.
David Aldridge
@Tony, when comparing runs, keep in mind that Chad's version stops processing the inner subquery after fetching 60 records, whereas Nick's has to compute the "row_number" for *all* records in the subquery. I prefer Nick's analytic solution, but it will run slower as the JOB table grows larger.
jimmyorr
Edited per everyone's suggestions.
Nick
@uglysmurf: I don't think that's correct - my tests (see my answer) were on a pretty large table (copy of all_objects) and the autotrace plans show a STOPKEY in both cases. Of course, the results may be different in older Oracle versions.
Tony Andrews
@Tony, thanks for pointing that out and setting me straight! I thought stopkey only worked with rownum...it looks like Oracle added an analytic stopkey named "window nosort stopkey" in 10.2...pretty smart! More info here: http://www.juliandyke.com/Optimisation/Operations/WindowNoSortStopkey.html
jimmyorr
Very nice! The order by is strange though, there is only one emplid here (because of the where clause). Maybe change it in the example to something else (like effdt)
Thilo
Link to an asktom article on this topic (he uses Chad's approach): http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
jimmyorr
@uglysmurf, I posted another "Ask Tom" article where he shows the row_number() approach, which was written 5 months after the article you show there.
Nick
+7  A: 
Tony Andrews
Hm. If that isn't above and beyond, then I don't know what is. ;-) +1
Tomalak
Yes, it's a sad indictment of my afternoon!
Tony Andrews