Contenido de esta guía
Qué hace ROW_NUMBER
ROW_NUMBER() asigna los números 1, 2, 3… a las filas de un resultado. La función no agrupa ni elimina filas: añade una columna calculada que indica la posición de cada fila dentro de su ventana.
El orden se define dentro de OVER. Si también utilizas PARTITION BY, la numeración vuelve a empezar en 1 para cada grupo.
Sintaxis
ROW_NUMBER() OVER (
PARTITION BY columna_grupo
ORDER BY columna_orden, columna_desempate
)PARTITION BY es opcional. Para una numeración reproducible, define ORDER BY dentro de OVER: SQL Server lo exige; SQLite permite omitirlo, pero entonces numera las filas en un orden arbitrario, y PostgreSQL tampoco garantiza un orden estable si no lo especificas. Añadir un criterio de desempate estable, como una clave primaria, evita que dos filas empatadas intercambien posiciones entre ejecuciones.
Ejemplo guiado
SELECT categoria, nombre, precio,
ROW_NUMBER() OVER (
PARTITION BY categoria
ORDER BY precio DESC, id
) AS posicion
FROM productos
WHERE categoria IN ('Accesorios', 'Pantallas')
ORDER BY categoria, posicion;| categoria | nombre | precio | posicion |
|---|---|---|---|
| Accesorios | Teclado | 49.5 | 1 |
| Accesorios | Ratón | 24.9 | 2 |
| Accesorios | Cable USB-C | 12.0 | 3 |
| Pantallas | Monitor 27 | 249.0 | 1 |
| Pantallas | Monitor 24 | 179.0 | 2 |
La secuencia se reinicia al cambiar de categoría. Dentro de cada categoría, el producto más caro ocupa la posición 1.
ROW_NUMBER no es lo mismo que RANK. Con empates, ROW_NUMBER entrega números distintos a cada fila. RANK asigna la misma posición a las filas empatadas y deja huecos después.
Error frecuente
Ordenar solo por una columna que puede empatar
Si dos productos tienen el mismo precio y el ORDER BY de la ventana solo usa precio DESC, el motor no tiene una regla completa para decidir cuál va primero.
Añadir id como segundo criterio no cambia el orden por precio; únicamente resuelve los empates de forma estable.
Comprueba lo aprendido
Numera pedidos de cada cliente
Muestra cliente_id, id, fecha y una columna numero_pedido. La numeración debe empezar en 1 para cada cliente y seguir el orden cronológico.
cliente_id.fecha.id para desempatar pedidos del mismo día.Solución razonada
SELECT cliente_id, id, fecha,
ROW_NUMBER() OVER (
PARTITION BY cliente_id
ORDER BY fecha, id
) AS numero_pedido
FROM pedidos
ORDER BY cliente_id, numero_pedido;PARTITION BY reinicia la secuencia para cada cliente y el par fecha, id define un orden completo.
Compatibilidad entre motores
ROW_NUMBER está disponible en PostgreSQL, MySQL 8.0 o posterior, SQLite 3.25 o posterior, SQL Server y Oracle. La sintaxis principal es similar. Las diferencias suelen aparecer al filtrar por el número calculado: en muchos motores necesitas una subconsulta o CTE porque el alias todavía no está disponible en WHERE de la misma consulta.
Qué debes recordar
ROW_NUMBERconserva todas las filas y añade una posición.- Usa
ORDER BYdentro deOVERpara controlar y hacer reproducible la numeración. PARTITION BYreinicia la secuencia por grupo.- Un criterio de desempate evita posiciones inestables.