As an extension of accepted answer Oracle internally uses ROW_NUMBER/RANK
functions. OFFSET FETCH
syntax is a syntax sugar.
It could be observed by using DBMS_UTILITY.EXPAND_SQL_TEXT
procedure:
Preparing sample:
CREATE TABLE rownum_order_test ( val NUMBER);INSERT ALL INTO rownum_order_testSELECT levelFROM dualCONNECT BY level <= 10;COMMIT;
Query:
SELECT valFROM rownum_order_testORDER BY val DESCFETCH FIRST 5 ROWS ONLY;
is regular:
SELECT "A1"."VAL""VAL"FROM (SELECT "A2"."VAL""VAL","A2"."VAL""rowlimit_$_0", ROW_NUMBER() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rownumber" FROM "ROWNUM_ORDER_TEST""A2") "A1"WHERE "A1"."rowlimit_$$_rownumber"<=5 ORDER BY "A1"."rowlimit_$_0" DESC;
Fetching expanded SQL text:
declare x VARCHAR2(1000);begin dbms_utility.expand_sql_text( input_sql_text => ' SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY', output_sql_text => x); dbms_output.put_line(x);end;/
WITH TIES
is expanded as RANK
:
declare x VARCHAR2(1000);begin dbms_utility.expand_sql_text( input_sql_text => ' SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS WITH TIES', output_sql_text => x); dbms_output.put_line(x);end;/SELECT "A1"."VAL""VAL"FROM (SELECT "A2"."VAL""VAL","A2"."VAL""rowlimit_$_0", RANK() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rank" FROM "ROWNUM_ORDER_TEST""A2") "A1"WHERE "A1"."rowlimit_$$_rank"<=5 ORDER BY "A1"."rowlimit_$_0" DESC
and offset:
declare x VARCHAR2(1000);begin dbms_utility.expand_sql_text( input_sql_text => ' SELECT valFROM rownum_order_testORDER BY valOFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY', output_sql_text => x); dbms_output.put_line(x);end;/SELECT "A1"."VAL""VAL"FROM (SELECT "A2"."VAL""VAL","A2"."VAL""rowlimit_$_0", ROW_NUMBER() OVER ( ORDER BY "A2"."VAL") "rowlimit_$$_rownumber" FROM "ROWNUM_ORDER_TEST""A2") "A1" WHERE "A1"."rowlimit_$$_rownumber"<=CASE WHEN (4>=0) THEN FLOOR(TO_NUMBER(4)) ELSE 0 END +4 AND "A1"."rowlimit_$$_rownumber">4 ORDER BY "A1"."rowlimit_$_0"