usar top registros optimizar numero limitar ejemplos consultas consulta como sql oracle pagination limit

sql - registros - select top oracle



¿Cómo limito el número de filas devueltas por una consulta de Oracle después de ordenar? (14)

¿Hay alguna manera de hacer que una consulta de Oracle comporte como si contuviera una cláusula de MySQL limit ?

En MySQL , puedo hacer esto:

select * from sometable order by name limit 20,10

para obtener las filas 21 a 30 (salta las primeras 20, da las siguientes 10). Las filas se seleccionan después del order by , order by lo que realmente comienza en el vigésimo nombre alfabéticamente.

En Oracle , lo único que mencionan las personas es la pseudo-columna de rownum , pero se evalúa antes de order by , lo que significa esto:

select * from sometable where rownum <= 10 order by name

devolverá un conjunto aleatorio de diez filas ordenadas por nombre, que no suele ser lo que quiero. Tampoco permite especificar un desplazamiento.


(sin probar) algo como esto puede hacer el trabajo

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

También está el rango de función analítica, que puede utilizar para ordenar.


A partir de Oracle 12c R1 (12.1), hay una cláusula de limitación de fila . No usa la sintaxis LIMIT familiar, pero puede hacer el trabajo mejor con más opciones. Puedes encontrar la sintaxis completa aquí .

Para responder a la pregunta original, aquí está la consulta:

SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

(Para versiones anteriores de Oracle, consulte otras respuestas en esta pregunta)

Ejemplos:

Los siguientes ejemplos fueron citados de la página enlazada , con la esperanza de prevenir la rotura del enlace.

Preparar

CREATE TABLE rownum_order_test ( val NUMBER ); INSERT ALL INTO rownum_order_test SELECT level FROM dual CONNECT BY level <= 10; COMMIT;

¿Qué hay en la mesa?

SELECT val FROM rownum_order_test ORDER BY val; VAL ---------- 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 20 rows selected.

Obtener las primeras N filas

SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY; VAL ---------- 10 10 9 9 8 5 rows selected.

Obtén las primeras N filas, si la fila N tiene vínculos, obtén todas las filas atadas

SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS WITH TIES; VAL ---------- 10 10 9 9 8 8 6 rows selected.

Top x % de filas

SELECT val FROM rownum_order_test ORDER BY val FETCH FIRST 20 PERCENT ROWS ONLY; VAL ---------- 1 1 2 2 4 rows selected.

Usando un offset, muy útil para la paginación.

SELECT val FROM rownum_order_test ORDER BY val OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY; VAL ---------- 3 3 4 4 4 rows selected.

Puedes combinar offset con porcentajes

SELECT val FROM rownum_order_test ORDER BY val OFFSET 4 ROWS FETCH NEXT 20 PERCENT ROWS ONLY; VAL ---------- 3 3 4 4 4 rows selected.


Empecé a prepararme para el examen Oracle 1z0-047, validado contra 12c Mientras preparaba para él, encontré una mejora de 12c conocida como ''FETCH FIRST''. Le permite buscar filas / filas de límites según su conveniencia. Varias opciones están disponibles con él.

- FETCH FIRST n ROWS ONLY - OFFSET n ROWS FETCH NEXT N1 ROWS ONLY // leave the n rows and display next N1 rows - n % rows via FETCH FIRST N PERCENT ROWS ONLY

Ejemplo:

Select * from XYZ a order by a.pqr FETCH FIRST 10 ROWS ONLY


En Oracle 12c (ver cláusula de limitación de fila en referencia de SQL ):

SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;


En oracle

SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY;

VAL

10 10 9 9 8

5 filas seleccionadas.

SQL>


Hice algunas pruebas de rendimiento para los siguientes enfoques:

Asktom

select * from ( select a.*, ROWNUM rnum from ( <select statement with order by clause> ) a where rownum <= MAX_ROW ) where rnum >= MIN_ROW

Analítico

select * from ( <select statement with order by clause> ) where myrow between MIN_ROW and MAX_ROW

Alternativa Corta

select * from ( select statement, rownum as RN with order by clause ) where a.rn >= MIN_ROW and a.rn <= MAX_ROW

Resultados

La tabla tenía 10 millones de registros, ordenados en una fila de fecha y hora no indexada:

  • El plan de explicación mostró el mismo valor para los tres seleccionados (323168)
  • Pero el ganador es AskTom (con un seguimiento analítico muy cerca)

Seleccionando las primeras 10 filas tomó:

  • AskTom: 28-30 segundos
  • Analítica: 33-37 segundos.
  • Alternativa corta: 110-140 segundos

Seleccionando filas entre 100,000 y 100,010:

  • AskTom: 60 segundos
  • Analítica: 100 segundos.

Seleccionando filas entre 9,000,000 y 9,000,010:

  • AskTom: 130 segundos
  • Analítica: 150 segundos.

Igual que el anterior con correcciones. Funciona pero definitivamente no es bonito.

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

Honestamente, mejor usar las respuestas anteriores.


Las consultas de paginación con orden son realmente difíciles en Oracle.

Oracle proporciona una pseudocolumna ROWNUM que devuelve un número que indica el orden en que la base de datos selecciona la fila de una tabla o conjunto de vistas unidas.

ROWNUM es una pseudocolumna que causa problemas a muchas personas. Un valor ROWNUM no se asigna permanentemente a una fila (esto es un malentendido común). Puede ser confuso cuando se asigna realmente un valor ROWNUM. Se asigna un valor ROWNUM a una fila después de que pasa los predicados de filtro de la consulta pero antes de la agregación o clasificación de la consulta.

Además, un valor ROWNUM se incrementa solo después de que se asigna.

Es por esto que la siguiente consulta no devuelve filas:

select * from (select * from some_table order by some_column) where ROWNUM <= 4 and ROWNUM > 1;

La primera fila del resultado de la consulta no pasa el predicado ROWNUM> 1, por lo que ROWNUM no se incrementa a 2. Por esta razón, ningún valor ROWNUM obtiene más de 1, por lo tanto, la consulta no devuelve filas.

La consulta correctamente definida debería tener este aspecto:

select * from (select *, ROWNUM rnum from (select * from skijump_results order by points) where ROWNUM <= 4) where rnum > 1;

Obtenga más información sobre las consultas de paginación en mis artículos en el blog de Vertabelo :


Menos sentencias SELECT. Además, consume menos rendimiento. Créditos a: [email protected]

SELECT * FROM (SELECT t.*, rownum AS rn FROM shhospede t) a WHERE a.rn >= in_first AND a.rn <= in_first;


Para cada fila devuelta por una consulta, la pseudocolumna ROWNUM devuelve un número que indica el orden en que Oracle selecciona la fila de una tabla o conjunto de filas unidas. La primera fila seleccionada tiene un ROWNUM de 1, la segunda tiene 2 y así sucesivamente.

SELECT * FROM sometable1 so WHERE so.id IN ( SELECT so2.id from sometable2 so2 WHERE ROWNUM <=5 ) AND ROWNUM <= 100

He implementado esto en oracle server 11.2.0.1.0


Puedes usar una subconsulta para esto como

select * from ( select * from emp order by sal desc ) where ROWNUM <= 5;

Consulte también el tema En ROWNUM y limite los resultados en Oracle / AskTom para obtener más información.

Actualización : para limitar el resultado con los límites inferior y superior, las cosas se hinchan un poco más 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;

(Copiado de un artículo AskTom específico)

Actualización 2 : A partir de Oracle 12c (12.1), hay una sintaxis disponible para limitar filas o comenzar en las compensaciones.

SELECT * FROM sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

Vea esta respuesta para más ejemplos. Gracias a Krumia por la pista.


Si no está en Oracle 12C, puede usar la consulta TOP N como se muestra a continuación.

SELECT * FROM ( SELECT rownum rnum , a.* FROM sometable a ORDER BY name ) WHERE rnum BETWEEN 10 AND 20;

Incluso puede mover esto de cláusula con cláusula de la siguiente manera

WITH b AS ( SELECT rownum rnum , a.* FROM sometable a ORDER BY name ) SELECT * FROM b WHERE rnum BETWEEN 10 AND 20;

Aquí en realidad estamos creando una vista en línea y cambiando el nombre de rownum como rnum. Puede utilizar rnum en la consulta principal como criterios de filtro.


Una solución analítica con una sola consulta anidada:

SELECT * FROM ( SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t ) WHERE MyRow BETWEEN 10 AND 20;

Rank() podría sustituirse por Row_Number() pero podría devolver más registros de los que espera si hay valores duplicados para el nombre.


select * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, FROM EMP ) EMP where ROWID=5

mayor que los valores descubren

select * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, FROM EMP ) EMP where ROWID>5

menos entonces los valores descubren

select * FROM (SELECT ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, FROM EMP ) EMP where ROWID=5