C'è un modo per far sì che una query Oracle
si comporti come se contenesse una clausola MySQL limit
?
In MySQL
, posso fare questo:
select *
from sometable
order by name
limit 20,10
per ottenere le righe dalla 21esima alla 30esima (saltare le prime 20, dare le successive 10). Le righe sono selezionate dopo il order by
, quindi inizia davvero dal 20° nome in ordine alfabetico.
In Oracle
, l'unica cosa che la gente menziona è la pseudo-colonna rownum
, ma viene valutata prima di order by
, il che significa questo:
select *
from sometable
where rownum <= 10
order by name
restituirà un insieme casuale di dieci righe ordinate per nome, che di solito non è quello che voglio. Inoltre non permette di specificare un offset.
Puoi usare una subquery per questo come
select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;
Dai anche un'occhiata all'argomento Su ROWNUM e limitazione dei risultati su Oracle/AskTom per maggiori informazioni.
Aggiornamento: Per limitare il risultato con entrambi i limiti inferiori e superiori le cose diventano un po' più gonfie con
select * from
( select a.*, ROWNUM rnum from
( <your_query_goes_here, with order by> ) a
where ROWNUM <= :MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
(Copiato da un articolo specifico di AskTom)
Aggiornamento 2: A partire da Oracle 12c (12.1) c'è una sintassi disponibile per limitare le righe o iniziare da offset.
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
Vedi questa risposta per ulteriori esempi. Grazie a Krumia per il suggerimento.
Una soluzione analitica con una sola query annidata:
SELECT * FROM
(
SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
)
WHERE MyRow BETWEEN 10 AND 20;
Rank()
potrebbe essere sostituito da Row_Number()
ma potrebbe restituire più record di quanto ci si aspetta se ci sono valori duplicati per il nome.
(non testato) qualcosa come questo potrebbe fare il lavoro
WITH
base AS
(
select * -- get the table
from sometable
order by name -- in the desired order
),
twenty AS
(
select * -- get the first 30 rows
from base
where rownum < 30
order by name -- in the desired order
)
select * -- then get rows 21 .. 30
from twenty
where rownum > 20
order by name -- in the desired order
C'è anche la funzione analitica rank, che potete usare per ordinare per.