Skip to content
Empieza gratis

¿Qué diferencia hay entre ROW_NUMBER, RANK y DENSE_RANK?

Ve a las tres funciones de ranking tratar el mismo empate y elige la que tu pregunta necesita.

Curso gratis. Tu Maestro, una IA, .

En la sucursal Norte, marzo y julio de 2025 vendieron exactamente lo mismo: 132,700 pesos. Si ordenas los meses de mayor a menor venta, ¿qué lugar le toca a cada uno? Depende de qué función uses:

  • ROW_NUMBER() numera 1, 2, 3… sin repetir nunca. A dos empatados les da números distintos.
  • RANK() da el mismo número a los empatados y luego salta: si dos quedan en 9, el siguiente es 11.
  • DENSE_RANK() da el mismo número a los empatados y no salta: si dos quedan en 9, el siguiente es 10.

Las tres se escriben igual, con OVER (ORDER BY ventas DESC). Ninguna necesita argumentos: lo que cambia es cómo cuentan cuando dos filas valen lo mismo en ese ORDER BY. A esas filas empatadas la documentación de DuckDB les llama peers, pares.

Inténtalo

Enero de Norte vendió 128,900 pesos y va justo después del empate. Antes de correr, comprométete con los tres números que crees que le tocan. Luego escribe la consulta con las tres funciones a la vez.

Comprueba lo que sabes: Antes de correr: marzo y julio de Norte empatan en el lugar 9. Enero va justo después. ¿Qué le dan a enero ROW_NUMBER, RANK y DENSE_RANK, en ese orden?

Para la sucursal Norte, regresa mes, ventas y tres columnas, todas de mayor a menor venta: fila con ROWNUMBER() (desempata con mes), rango con RANK() y rangodenso con DENSERANK(). Ordena el resultado por fila. Terminaste cuando ves 12 filas y marzo y julio tienen el mismo rango.

Tu turno

Para la sucursal Norte, regresa mes, ventas y tres columnas, todas de mayor a menor venta: fila con ROW_NUMBER() (desempata con mes), rango con RANK() y rango_denso con DENSE_RANK(). Ordena el resultado por fila. Terminaste cuando ves 12 filas y marzo y julio tienen el mismo rango.

Tablas: ventas_mensuales (sucursal, mes, ventas)

ventas_mensuales · 35 filas

ColumnaTipo
sucursal Nombre de la sucursal: Centro, Norte o Sur.VARCHAR
mes Primer día del mes que resume la fila.DATE
ventas Ventas del mes, en pesos.BIGINT

Primeras filas

sucursalmesventas
Centro2025-01-01165100
Centro2025-02-01155700
Centro2025-03-01178700

Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras.

Listo para ejecutar tu consulta.

Ejecútalo tú

Estas son las filas alrededor del empate, tal como salieron al correr la solución en el sandbox de Maestro:

mesventasfilarangorango_denso
2025-04-01137900777
2025-10-01137200888
2025-03-01132700999
2025-07-011327001099
2025-01-01128900111110
2025-02-01127300121211

Arriba del empate, las tres columnas dicen lo mismo. Por eso es tan fácil creer que son intercambiables: en la mayoría de los ejemplos no hay empates. La diferencia aparece justo en el empate y después.

¿Cuál usar? Pregúntate qué quieres que pase con un empate:

  • Un número único por fila (para quedarte con exactamente una): ROW_NUMBER(), con un desempate en el ORDER BY.
  • "Los que quedaron en los 3 primeros lugares", empates incluidos: RANK(), que cuenta cuántos quedaron arriba.
  • "Los 3 valores más altos", aunque los compartan varios: DENSE_RANK().

Así se ven los doce meses de Norte ordenados de mayor a menor venta. Las dos barras resaltadas son el empate: la misma altura, el mismo valor. Para RANK() y DENSE_RANK() son el mismo lugar; para ROW_NUMBER() una tiene que ir antes que la otra.

Datos sintéticos del curso (CC0). Resaltados, los dos meses empatados.

Los empates que te van a salir

Un empate hasta arriba. Si dos meses empatan en el primer lugar, RANK() da 1, 1 y después 3: no hay segundo lugar. DENSE_RANK() da 1, 1 y 2. Si tu reporte dice "el segundo mejor mes", decide antes qué significa con un empate en el primero.

Un valor que falta. Una fila con NULL en la columna que ordenas también recibe un lugar. En una corrida en el sandbox con cuatro filas, una de ellas NULL, RANK() OVER (ORDER BY x DESC) le dio el lugar 4, el último: en DuckDB los NULL van al final también en orden descendente. Si no quieres que una fila sin dato compita, quítala antes con WHERE x IS NOT NULL.

Un empate que no ves. ROW_NUMBER() sin desempate no te avisa que hubo un empate: simplemente elige. Si un ranking va a un reporte que alguien lee, revisa con RANK() si hay empates en el corte, aunque al final uses ROW_NUMBER().

La pregunta de entrevista más vieja con empates es "¿cuál es el segundo valor más alto?", la del segundo salario más alto, ahora por grupo. Con DENSE_RANK() = 2 obtienes el segundo valor distinto, aunque el primero lo compartan varios. En Norte, la corrida dio noviembre, con 156,600 pesos, como rango_denso 2. Otra forma común: "los tres productos más vendidos de cada categoría, incluyendo empates". Ahí la palabra "incluyendo" decide entre RANK() y ROW_NUMBER(). Si te piden un top N con empates y no sabes qué función elegir, cuéntale a tu Maestro tu caso.

Cuando entregues un top 10, escribe junto al resultado qué hiciste con los empates. "Top 10, empates incluidos (12 filas)" evita la pregunta de por qué hay 12, y "top 10 por ventas, desempatado por fecha" evita que alguien crea que el décimo lugar es único.

Consejo: Por qué fila desempata con mes

Sin mes en el ORDER BY de ROW_NUMBER(), nada dice cuál de los dos meses empatados es el 9 y cuál el 10. Con RANK() y DENSE_RANK() no hace falta: a los empatados les toca el mismo número.

Comprueba lo que sabes: En Norte, marzo y julio empatan en el lugar 9 con DENSE_RANK. ¿Qué número le da DENSE_RANK a enero, el mes que sigue?

Comprueba lo que sabes: Quieres premiar a los meses que quedaron en los 3 primeros lugares y, si hay empate en el tercero, premiar a todos los empatados. ¿Qué función usas para numerar?