¿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
| Columna | Tipo |
|---|---|
| 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
| sucursal | mes | ventas |
|---|---|---|
| Centro | 2025-01-01 | 165100 |
| Centro | 2025-02-01 | 155700 |
| Centro | 2025-03-01 | 178700 |
Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras. Tab agrega sangría; para salir del editor, presiona Escape y luego Tab.
Listo para ejecutar tu consulta.
Estas son las filas alrededor del empate, tal como salieron al correr la solución en el sandbox de Maestro:
| mes | ventas | fila | rango | rango_denso |
|---|---|---|---|---|
| 2025-04-01 | 137900 | 7 | 7 | 7 |
| 2025-10-01 | 137200 | 8 | 8 | 8 |
| 2025-03-01 | 132700 | 9 | 9 | 9 |
| 2025-07-01 | 132700 | 10 | 9 | 9 |
| 2025-01-01 | 128900 | 11 | 11 | 10 |
| 2025-02-01 | 127300 | 12 | 12 | 11 |
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 elORDER 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.
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.