Czy istnieje sposób, aby zapytanie Oracle
zachowywało się tak, jakby zawierało klauzulę MySQL limit
?
W MySQL
mogę to zrobić:
select *
from sometable
order by name
limit 20,10
aby uzyskać wiersze od 21 do 30 (pomiń pierwsze 20, podaj następne 10). Wiersze są wybierane po order by
, więc tak naprawdę zaczyna się od 20. nazwiska alfabetycznie.
W Oracle
jedyną rzeczą, o której ludzie wspominają, jest pseudokolumna rownum
, ale jest ona oceniana przed order by
, co oznacza to:
select *
from sometable
where rownum <= 10
order by name
zwróci losowy zestaw dziesięciu wierszy uporządkowanych według nazwy, co zazwyczaj nie jest tym, czego chcę. Nie pozwala również na określenie offsetu.
Możesz użyć do tego podzapytania, np.
select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;
Zajrzyj też do tematu O ROWNUM i ograniczaniu wyników na Oracle/AskTom po więcej informacji.
Uaktualnienie: Aby ograniczyć wynik zarówno z dolną jak i górną granicą rzeczy stają się nieco bardziej rozdęte z
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;
(Skopiowane z określonego artykułu AskTom-article)
Uaktualnienie 2: Począwszy od Oracle 12c (12.1) dostępna jest składnia do ograniczania wierszy lub rozpoczynania na offsecie.
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
Zobacz ta odpowiedź, aby uzyskać więcej przykładów. Podziękowania dla Krumia za podpowiedź.
Rozwiązanie analityczne z tylko jednym zagnieżdżonym zapytaniem:
SELECT * FROM
(
SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
)
WHERE MyRow BETWEEN 10 AND 20;
Rank()
może być zastąpiony przez Row_Number()
, ale może zwrócić więcej rekordów niż oczekujesz, jeśli istnieją zduplikowane wartości dla nazwy.
(niesprawdzone) coś takiego może wykonać pracę
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
Istnieje również funkcja analityczna rank, której możesz użyć do zamówienia przez.