Cláusula de limitación de filas para consultas Top-N en Oracle Database 12c versión 1 (12.1)

  • Introducción
  • Preparar
  • Consultas Top-N
  • Paginación a través de datos
  • Información extra
  • Transformación de consultas

Introducción

Una consulta Top-N se utiliza para recuperar las N filas superiores o inferiores de un conjunto ordenado. La combinación de dos consultas Top-N le brinda la posibilidad de recorrer un conjunto ordenado. Este concepto no es nuevo. De hecho, Oracle ya ofrece varias formas de realizar consultas Top-N, como se explica aquí. Estos métodos funcionan bien, pero parecen bastante complicados en comparación con los métodos proporcionados por otros motores de bases de datos. Por ejemplo, MySQL usa una cláusula LIMIT para desplazarse por un conjunto de resultados ordenado.

SELECT * 
FROM   my_table 
ORDER BY column_1
LIMIT 0 , 40

Oracle 12c ha introducido la cláusula de limitación de filas para simplificar las consultas Top-N y la paginación a través de conjuntos de resultados ordenados.

Preparar

Para ser coherentes, usaremos la misma tabla de ejemplo utilizada en el artículo de Consultas Top-N.
Crea y completa una tabla de prueba.

DROP TABLE rownum_order_test;

CREATE TABLE rownum_order_test (
  val  NUMBER
);

INSERT ALL
  INTO rownum_order_test
  INTO rownum_order_test
SELECT level
FROM   dual
CONNECT BY level <= 10;

COMMIT;

La siguiente consulta muestra que tenemos 20 filas con 10 valores distintos.

SELECT val
FROM   rownum_order_test
ORDER BY val;

       VAL
----------
         1
         1
         2
         2
         3
         3
         4
         4
         5
         5
         6

       VAL
----------
         6
         7
         7
         8
         8
         9
         9
        10
        10

20 rows selected.

SQL>

Consultas Top-N

La sintaxis de la cláusula de limitación de filas parece un poco complicada a primera vista.

[ OFFSET offset { ROW | ROWS } ]
[ FETCH { FIRST | NEXT } [ { rowcount | percent PERCENT } ]
    { ROW | ROWS } { ONLY | WITH TIES } ]

En realidad, para la consulta clásica de Top-N es muy simple. El siguiente ejemplo devuelve los 5 valores más grandes de un conjunto ordenado. El uso de la cláusula ONLY limita el número de filas devueltas al número exacto solicitado.

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

       VAL
----------
        10
        10
         9
         9
         8

5 rows selected.

SQL>

El uso de la cláusula WITH TIES puede dar como resultado que se devuelvan más filas si varias filas coinciden con el valor de la fila N-ésima. En este caso, la quinta fila tiene el valor «8», pero hay dos filas que empatan en el quinto lugar, por lo que se devuelven ambas.

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.

SQL>

Además de limitar por número de filas, la cláusula de limitación de filas también nos permite limitar por porcentaje de filas. La siguiente consulta devuelve el 20% inferior 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.

SQL>

Paginación a través de datos

Paginar a través de un conjunto de resultados ordenado fue un poco molesto con el enfoque clásico de consulta Top-N, ya que requería dos consultas Top-N, una anidada dentro de la otra. Por ejemplo, si quisiéramos el segundo bloque de 4 filas, podríamos hacer lo siguiente.

SELECT val
FROM   (SELECT val, rownum AS rnum
        FROM   (SELECT val
                FROM   rownum_order_test
                ORDER BY val)
        WHERE rownum <= 8) WHERE rnum >= 5;

       VAL
----------
         3
         3
         4
         4

4 rows selected.

SQL>

Con la cláusula de limitación de filas podemos lograr el mismo resultado utilizando la siguiente consulta.

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.

SQL>

El punto de partida para FETCH es OFFSET + 1.
El OFFSET siempre se basa en un número de filas, pero esto se puede combinar con un FETCH usando un PERCENT.

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.

SQL>

No es sorprendente que el desplazamiento, el recuento de filas y el porcentaje puedan, y probablemente deberían, ser variables de vinculación.

VARIABLE v_offset NUMBER;
VARIABLE v_next NUMBER;

BEGIN
  :v_offset := 4;
  :v_next   := 4;
END;
/

SELECT val
FROM   rownum_order_test
ORDER BY val
OFFSET :v_offset ROWS FETCH NEXT :v_next ROWS ONLY;

       VAL
----------
         3
         3
         4
         4

SQL>

Información extra

  •  Las palabras clave ROW y ROWS se pueden usar indistintamente, al igual que las palabras clave FIRST y NEXT. Elija los que escaneen mejor al leer el SQL como una oración.
  • Si no se especifica el desplazamiento, se supone que es 0.
  • Los valores negativos para el desplazamiento, el recuento de filas o el porcentaje se tratan como 0.
  • Los valores nulos para el desplazamiento, el recuento de filas o el porcentaje hacen que no se devuelvan filas.
  • Las porciones fraccionarias de desplazamiento, recuento de filas o porcentaje se truncan.
  • Si el desplazamiento es mayor o igual que el número total de filas del conjunto, no se devuelve ninguna fila.
  • Si el recuento de filas o el porcentaje son mayores que el número total de filas después del desplazamiento, se devuelven todas las filas.
  • La cláusula de limitación de filas no se puede utilizar con la cláusula FOR UPDATE, las pseudocolumnas de secuencia CURRVAL y NEXTVAL o en una vista materializada de actualización rápida.

Transformación de consultas

Vale la pena tener en cuenta que esta nueva funcionalidad es una transformación de consulta. Si tomamos una de las consultas anteriores y realizamos un rastreo 10053, podemos ver esto.
Compruebe el archivo de seguimiento de la sesión.

SELECT value FROM v$diag_info WHERE  name = 'Default Trace File';

VALUE
----------------------------------------------------------------
/u01/app/oracle/diag/rdbms/cdb1/cdb1/trace/cdb1_ora_15539.trc

1 row selected.

SQL>

Realice un rastreo 10053 de la declaración.

ALTER SESSION SET EVENTS '10053 trace name context forever';

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

ALTER SESSION SET EVENTS '10053 trace name context off';

La sección que comienza con «Consulta final después de las transformaciones» muestra la declaración que se procesó realmente, después de la transformación de la consulta.

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "from$_subquery$_002"."VAL" "VAL"
FROM  (SELECT "ROWNUM_ORDER_TEST"."VAL" "VAL",
              "ROWNUM_ORDER_TEST"."VAL" "rowlimit_$_0",
              ROW_NUMBER() OVER ( ORDER BY "ROWNUM_ORDER_TEST"."VAL" DESC ) "rowlimit_$$_rownumber"
       FROM "TEST"."ROWNUM_ORDER_TEST" "ROWNUM_ORDER_TEST") "from$_subquery$_002"
WHERE  "from$_subquery$_002"."rowlimit_$$_rownumber"<=5
ORDER BY "from$_subquery$_002"."rowlimit_$_0" DESC

Como puede ver, la declaración se ha reescrito a un formulario que podríamos haber utilizado antes de 12c.

Enlace rapido

jonathanlewis.wordpress.com
docs.oracle.com

1 comentario en “Cláusula de limitación de filas para consultas Top-N en Oracle Database 12c versión 1 (12.1)”

  1. Pingback: Consultas Top-N - DBandTech.com

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *