Ir al contenido principal
¿Te ayudamos?
oposiciones

ROW_NUMBER, RANK y DENSE_RANK: 8 ejercicios SQL

14 min de lectura

Resuelve ocho ejercicios SQL de ROW_NUMBER, RANK y DENSE_RANK: empates, particiones, ordenación y filtros. Consultas comprobadas en SQLite.

En estos ejercicios SQL de ROW_NUMBER, RANK y DENSE_RANK seguirás seis filas y distinguirás tres decisiones: cómo se dividen en particiones, qué valores definen un empate y en qué orden se presenta la salida. Dos consultas pueden mostrar las mismas filas y asignar posiciones distintas.

Son ocho preguntas originales con cuatro alternativas y soluciones razonadas. Las consultas se han comprobado en SQLite 3.46.1; la última contiene un error intencionado. Los datos son ficticios. Esta práctica complementa el trabajo con SELECT y subconsultas, sin atribuir estas funciones a un examen oficial ni acreditar ejecución en otros gestores.

Una base de prácticas con dos unidades y empates

Utiliza una base de datos de prácticas vacía. Ejecuta esta inicialización una sola vez. Para repetir desde cero, empieza en otra base vacía; no ejecutes la creación sobre tablas que ya existan.

CREATE TABLE practice_scores (
  id INTEGER PRIMARY KEY,
  unit TEXT NOT NULL,
  points INTEGER NOT NULL
);
INSERT INTO practice_scores (id, unit, points) VALUES
  (1, 'A', 90),
  (2, 'A', 80),
  (3, 'A', 80),
  (4, 'B', 95),
  (5, 'B', 95),
  (6, 'B', 70);
idunitpoints
1A90
2A80
3A80
4B95
5B95
6B70

Los ids son únicos, los puntos son enteros y no hay nulos. A tiene un empate en 80 puntos y B otro en 95. Todas las preguntas parten de estos mismos datos; las consultas no cambian las filas. La tabla anterior describe el contenido, no promete una ordenación física del almacenamiento.

Lee OVER y la consulta exterior por separado

Una función de ventana lleva una cláusula OVER. PARTITION BY unit separa A y B para el cálculo. El ORDER BY dentro de OVER determina el orden de numeración y, en RANK y DENSE_RANK, las filas empatadas. El ORDER BY exterior fija cómo se muestra el resultado.

FunciónCómo trata los empates del criterio de ventana
ROW_NUMBERDa un número diferente a cada fila
RANKComparte posición y deja saltos después de empates
DENSE_RANKComparte posición y cuenta niveles sin saltos

La documentación oficial de ventanas de SQLite explica las tres funciones, las particiones y la diferencia entre ordenar la ventana y ordenar la salida. Para contrastar las definiciones puedes consultar también la referencia de funciones de ventana de PostgreSQL 18. Aquí se han ejecutado consultas en SQLite; consultar otra documentación no equivale a probar otro motor.

Los registros, enunciados, consultas y alternativas de esta colección son propios. Antes de abrir cada solución, anota los ids que pertenecen a cada partición y sus posiciones. Si se pide una secuencia, sigue la ordenación final indicada, no el orden en que imaginaste que el motor recorrería la tabla.

Ejercicio 1. Numerar filas dentro de cada unidad

En el orden final de id ascendente, ¿qué secuencia devuelve la columna pos?

SELECT id,
       ROW_NUMBER() OVER (
         PARTITION BY unit ORDER BY points DESC, id ASC
       ) AS pos
FROM practice_scores
ORDER BY id ASC;

A. 1, 2, 3, 4, 5, 6.

B. 1, 2, 2, 1, 1, 3.

C. 1, 2, 3, 1, 2, 3.

D. 1, 2, 2, 1, 1, 2.

Ver solución del ejercicio 1

Correcta: C. ROW_NUMBER asigna un número diferente a cada fila de su partición. La unidad A contiene las filas 1, 2 y 3: reciben 1, 2 y 3. La unidad B contiene las filas 4, 5 y 6: vuelve a empezar en 1 y termina en 3. La secuencia pedida es 1, 2, 3, 1, 2, 3.

El segundo criterio id ASC resuelve de manera inequívoca los empates de puntos. A ignora la partición y sigue contando hasta seis. B utiliza la numeración de RANK; D, la de DENSE_RANK para estos datos. Aunque dos filas empaten en puntos, siguen siendo dos filas distintas: ROW_NUMBER no elimina ninguna ni comparte su número.

Ejercicio 2. RANK conserva el empate y deja saltos

En el orden final de id ascendente, ¿qué secuencia devuelve pos al ordenar la ventana solo por puntos?

SELECT id,
       RANK() OVER (
         PARTITION BY unit ORDER BY points DESC
       ) AS pos
FROM practice_scores
ORDER BY id ASC;

A. 1, 2, 2, 1, 1, 3.

B. 1, 2, 3, 1, 2, 3.

C. 1, 2, 2, 1, 1, 2.

D. 1, 1, 1, 1, 1, 1.

Ver solución del ejercicio 2

Correcta: A. En A, los 90 puntos ocupan la posición 1 y los dos registros de 80 comparten la 2. En B, los dos registros de 95 comparten la posición 1; el de 70 recibe la 3, porque hay dos filas por delante. La salida de pos es 1, 2, 2, 1, 1, 3.

B asigna números consecutivos como ROW_NUMBER. C cierra el salto como DENSE_RANK. D trataría todas las filas de cada partición como empatadas, pero aquí hay valores distintos de puntos. El id aparece en el ORDER BY exterior para presentar filas; no participa en el criterio de empate de la ventana. Los empates se conservan como filas, sin convertir cada pareja empatada en una sola fila.

Ejercicio 3. DENSE_RANK cuenta niveles sin saltos

Con la misma partición y los mismos puntos, ¿qué secuencia devuelve pos con DENSE_RANK?

SELECT id,
       DENSE_RANK() OVER (
         PARTITION BY unit ORDER BY points DESC
       ) AS pos
FROM practice_scores
ORDER BY id ASC;

A. 1, 2, 3, 1, 2, 3.

B. 1, 2, 2, 1, 1, 3.

C. 1, 1, 2, 1, 2, 2.

D. 1, 2, 2, 1, 1, 2.

Ver solución del ejercicio 3

Correcta: D. DENSE_RANK cuenta los niveles distintos de puntos dentro de cada unidad, sin dejar huecos. A tiene los niveles 90 y 80; B tiene 95 y 70. La columna pos, presentada por id, es 1, 2, 2, 1, 1, 2. En B, el nivel de 70 ocupa la segunda posición distinta aunque tenga dos filas delante.

A describe ROW_NUMBER con desempate por id. B corresponde al RANK del ejercicio anterior. C rompe empates de una manera que no sigue los niveles de puntos. Que RANK y DENSE_RANK coincidan en la unidad A no los hace equivalentes: la diferencia se observa después de un empate, y aquí la última fila de B permite distinguirlos.

Ejercicio 4. Añadir una clave cambia qué es un empate

¿Qué secuencia devuelve pos al añadir id al ORDER BY de la ventana de RANK?

SELECT id,
       RANK() OVER (
         PARTITION BY unit ORDER BY points DESC, id ASC
       ) AS pos
FROM practice_scores
ORDER BY id ASC;

A. 1, 2, 2, 1, 1, 3.

B. 1, 2, 3, 1, 2, 3.

C. 1, 1, 2, 1, 2, 2.

D. 1, 2, 2, 1, 1, 2.

Ver solución del ejercicio 4

Correcta: B. Las filas solo son pares para RANK cuando coinciden en todas las expresiones del ORDER BY de la ventana. El id es una clave única. Por tanto, aunque haya puntos iguales, las parejas (points, id) son distintas. Las posiciones quedan 1, 2, 3, 1, 2, 3.

A y D mantienen empates que existían al comparar únicamente puntos. C tampoco sigue el orden de las parejas. Añadir id da una ordenación inequívoca, pero también cambia el significado de RANK: ya no conserva el empate por puntuación. Si quieres mantener ese empate y presentar las filas por id, conserva id solo en la ordenación exterior, como en el ejercicio 2.

Ejercicio 5. Ordenar la ventana no ordena la presentación

Leyendo las filas tal como las devuelve el ORDER BY exterior, ¿qué secuencia muestra pos?

SELECT id,
       ROW_NUMBER() OVER (ORDER BY id ASC) AS pos
FROM practice_scores
ORDER BY id DESC;

A. 1, 2, 3, 4, 5, 6.

B. 6, 5, 4, 3, 2, 1.

C. 3, 2, 1, 3, 2, 1.

D. 1, 1, 1, 1, 1, 1.

Ver solución del ejercicio 5

Correcta: B. La ventana numera todas las filas por id ascendente, sin particiones por unidad: el id 1 recibe pos 1 y el id 6 recibe pos 6. Después, la consulta presenta los ids en sentido descendente: 6, 5, 4, 3, 2, 1. Esa es también la secuencia de pos que ves.

A confunde la ordenación usada para calcular con la que se exige para mostrar. C reinicia la numeración por unidad, aunque no hay PARTITION BY. D convierte todas las posiciones en uno. Cambiar el ORDER BY exterior no vuelve a calcular ROW_NUMBER: cambia el orden en que se muestran las filas ya numeradas. En una pregunta sobre secuencias, lee los dos ORDER BY por separado.

Ejercicio 6. WHERE elimina filas antes de numerar

Tras excluir id 1, ¿qué secuencia devuelve pos en el orden final de los cinco ids restantes?

SELECT id,
       ROW_NUMBER() OVER (
         PARTITION BY unit ORDER BY points DESC, id ASC
       ) AS pos
FROM practice_scores
WHERE id <> 1
ORDER BY id ASC;

A. 2, 3, 1, 2, 3.

B. 1, 2, 3, 4, 5.

C. 1, 2, 3, 1, 2, 3.

D. 1, 2, 1, 2, 3.

Ver solución del ejercicio 6

Correcta: D. El WHERE deja fuera la fila 1 antes de calcular la ventana. En A quedan los ids 2 y 3, que reciben pos 1 y 2. En B siguen los ids 4, 5 y 6, con pos 1, 2 y 3. La secuencia completa es 1, 2, 1, 2, 3.

A conserva las posiciones 2 y 3 que los ids 2 y 3 tenían en el primer ejercicio, como si el filtro se aplicara después. B omite la partición; C conserva incluso seis posiciones aunque ya solo hay cinco filas. La función trabaja sobre las filas que han sobrevivido al filtro de esta consulta. Para filtrar sobre un número de ventana ya calculado, necesitas otro nivel de consulta.

Ejercicio 7. Filtrar posiciones puede devolver más de dos filas

¿Qué secuencia de ids devuelve la consulta completa al conservar pos menor o igual que dos?

WITH classified AS (
  SELECT id, unit,
         RANK() OVER (
           PARTITION BY unit ORDER BY points DESC
         ) AS pos
  FROM practice_scores
)
SELECT id
FROM classified
WHERE pos <= 2
ORDER BY id ASC;

A. 1, 2, 3, 4, 5.

B. 1, 2, 4, 5.

C. 1, 2, 3, 4, 5, 6.

D. 1, 4, 5.

Ver solución del ejercicio 7

Correcta: A. La CTE calcula primero RANK por unidad. A tiene posiciones 1, 2, 2, así que entran sus tres filas. B tiene 1, 1, 3, así que entran solo los ids 4 y 5. El resultado son cinco ids: 1, 2, 3, 4 y 5. Pedir posición menor o igual que dos no obliga a obtener exactamente dos filas por unidad.

B sería el conjunto obtenido con ROW_NUMBER y un desempate por id al escoger las dos primeras filas por unidad. C conserva también el id 6 y correspondería aquí al criterio DENSE_RANK menor o igual que dos. D se queda únicamente con quienes tienen RANK igual a uno. La elección de función cambia qué significa seleccionar primeras posiciones cuando hay empates.

Ejercicio 8. Un alias de ventana no se filtra en el mismo WHERE

¿Qué ocurre al ejecutar esta consulta en SQLite con los datos iniciales?

SELECT id,
       ROW_NUMBER() OVER (
         PARTITION BY unit ORDER BY points DESC, id ASC
       ) AS pos
FROM practice_scores
WHERE pos = 1
ORDER BY id ASC;

A. Devuelve dos filas: ids 1 y 4.

B. Devuelve las seis filas con pos igual a uno.

C. Produce un error al filtrar el alias de ventana en ese WHERE.

D. Devuelve cero filas sin error.

Ver solución del ejercicio 8

Correcta: C. SQLite rechaza este uso del alias de una función de ventana en el WHERE del mismo nivel. No se obtiene una tabla de resultados que debas contar. Ese WHERE se procesa antes del cálculo de la ventana; el alias pos no permite trasladar automáticamente el filtro a un paso posterior.

A sería el resultado deseado si calcularas primero ROW_NUMBER en una CTE o subconsulta y filtraras pos igual a uno desde una consulta exterior. B inventa una renumeración de todas las filas; D convierte el error en una salida vacía. El ejercicio 7 muestra cómo separar los dos niveles, aunque allí se utiliza RANK y otro criterio. No presupongas que las reglas sobre alias ordinarios de un gestor autorizan este uso de una ventana.

Plantilla de respuestas y revisión

La clave es CADBBDAC. Los casos 1 a 4 comparan funciones y criterios de empate. El 5 separa cálculo y presentación. El 6 estudia qué filas ve la ventana. El 7 filtra un resultado ya calculado y el 8 obliga a reconocer un error antes de inventar una salida.

Si confundiste RANK y DENSE_RANK, revisa la fila 6: en su unidad hay dos filas empatadas por delante. Si añadiste id para ordenar y desaparecieron los empates, comprueba si lo pusiste dentro de OVER o solamente al final. Si obtuviste seis posiciones en el ejercicio 6, has olvidado aplicar el filtro previo.

El tutorial oficial de ventanas de PostgreSQL 18 explica la separación entre filtrado previo, cálculo de ventanas y filtrado mediante una consulta exterior. Esta práctica trabaja esos conceptos con consultas concretas de SQLite. No incluye marcos de agregación, tratamiento de nulos ni otras funciones de ventana: cada gestor y versión exige revisar su sintaxis.

Relación con otras prácticas y con el material informático

Para trabajar filas duplicadas y consultas compuestas, continúa con los ocho ejercicios de UNION, INTERSECT y EXCEPT. Para practicar relaciones y recuentos, tienes los ejercicios de JOIN, NULL y GROUP BY. Distingue siempre una función que añade una posición de un operador que agrupa, combina o elimina filas.

El material de Técnico/a Superior de Informática de A Coruña desarrolla SELECT, filtros, ordenación y subconsultas en su apartado de DML, redactado en gallego. Esta práctica amplía esos fundamentos con funciones de ventana. Es un producto de pago; consulta su ficha para valorar el alcance del material y compáralo con el programa de tu convocatoria.

Preguntas frecuentes

¿ROW_NUMBER da el mismo número a las filas empatadas?

No. Asigna un número diferente a cada fila dentro de su partición. Si quieres fijar cuál recibe cada número cuando los puntos empatan, añade una clave única al ORDER BY de esa ventana.

¿Qué diferencia hay entre RANK y DENSE_RANK?

Los dos comparten posición cuando las filas empatan según todas las expresiones de ordenación de la ventana. RANK deja saltos tras los empates; DENSE_RANK cuenta niveles distintos sin saltos. En el ejercicio 2, la unidad B recibe 1, 1, 3; en el 3 recibe 1, 1, 2.

¿PARTITION BY reduce cada unidad a una sola fila?

No. En estas consultas las filas mantienen su identidad. PARTITION BY separa los conjuntos sobre los que se calcula la función; la numeración vuelve a empezar dentro de cada partición.

¿El ORDER BY dentro de OVER fija el orden de la salida?

No basta para exigir el orden final de presentación. En el ejercicio 5 la ventana numera por id ascendente y la consulta muestra por id descendente. Usa un ORDER BY exterior cuando importe la secuencia devuelta.

¿Cómo filtro por una posición calculada con una ventana?

Calcula la posición en una CTE o subconsulta y aplica el filtro en una consulta exterior. El ejercicio 7 separa ambos niveles; el 8 contiene deliberadamente un filtro inválido en el mismo WHERE de SQLite.