La cláusula PARTITION BY en SQL se utiliza dentro de las funciones de ventana para dividir un conjunto de resultados en grupos (particiones) sobre los cuales se aplicará un cálculo.
👉 Es similar a GROUP BY, pero con una diferencia importante: PARTITION BY no agrupa ni reduce filas, sino que conserva todas las filas y calcula el valor por partición.
Se suele usar con funciones como ROW_NUMBER(), RANK(), SUM(), AVG(), MIN(), MAX(), entre otras.
Sintaxis básica de PARTITION BY
SELECT columnas,
funcion() OVER (PARTITION BY columna ORDER BY columna2)
FROM tabla;
Elementos clave:
funcion()→ función de ventana (ej.ROW_NUMBER(),SUM(), etc.).OVER→ indica que es una función de ventana.PARTITION BY→ divide las filas en grupos.ORDER BY(opcional) → ordena dentro de cada partición.
Si no conocés bien cómo funciona el ORDER BY dentro de OVER, revisá el artículo dedicado.
Ejemplo básico de PARTITION BY
Tabla ventas:
| id | cliente_id | total |
|---|---|---|
| 1 | 1 | 100 |
| 2 | 1 | 200 |
| 3 | 2 | 150 |
| 4 | 2 | 300 |
| 5 | 3 | 400 |
Consulta:
SELECT cliente_id,
total,
SUM(total) OVER (PARTITION BY cliente_id) AS total_por_cliente
FROM ventas;
Resultado:
| cliente_id | total | total_por_cliente |
|---|---|---|
| 1 | 100 | 300 |
| 1 | 200 | 300 |
| 2 | 150 | 450 |
| 2 | 300 | 450 |
| 3 | 400 | 400 |
👉 Cada cliente conserva todas sus filas, pero aparece el total de sus compras en cada una.
Diferencia entre GROUP BY y PARTITION BY
- GROUP BY: agrupa y devuelve una fila por grupo.
- PARTITION BY: conserva todas las filas y agrega el valor calculado por grupo.
Ejemplo con GROUP BY:
SELECT cliente_id, SUM(total) AS total_por_cliente
FROM ventas
GROUP BY cliente_id;
Resultado:
| cliente_id | total_por_cliente |
|---|---|
| 1 | 300 |
| 2 | 450 |
| 3 | 400 |
👉 Aquí perdemos el detalle de cada compra.
Con PARTITION BY, mantenemos las filas individuales y además el total.
Ejemplo práctico: ranking de ventas por cliente
SELECT cliente_id,
total,
ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY total DESC) AS ranking
FROM ventas;
Resultado:
| cliente_id | total | ranking |
|---|---|---|
| 1 | 200 | 1 |
| 1 | 100 | 2 |
| 2 | 300 | 1 |
| 2 | 150 | 2 |
| 3 | 400 | 1 |
👉 Devuelve un ranking de compras dentro de cada cliente.
Ejemplo: promedio por departamento
SELECT nombre,
departamento,
salario,
AVG(salario) OVER (PARTITION BY departamento) AS promedio_dep
FROM empleados;
👉 Cada empleado conserva su fila, pero se muestra también el salario promedio de su departamento.
Ejemplo: primer pedido por cliente
SELECT cliente_id,
fecha,
ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY fecha ASC) AS orden
FROM pedidos;
👉 Permite identificar cuál fue el primer pedido de cada cliente.
PARTITION BY sin ORDER BY
Si usamos solo PARTITION BY sin ORDER BY, la función se aplica al grupo completo sin importar el orden.
Ejemplo:
SELECT cliente_id,
COUNT(*) OVER (PARTITION BY cliente_id) AS num_pedidos
FROM pedidos;
👉 Devuelve el número total de pedidos por cliente en cada fila.
Errores comunes con PARTITION BY
- Confundirlo con GROUP BY
👉 GROUP BY reduce filas, PARTITION BY no. - Olvidar el ORDER BY dentro de OVER cuando se necesita ranking
ROW_NUMBER() OVER (PARTITION BY cliente_id) -- ❌ No define orden
- Esperar que PARTITION BY funcione fuera de OVER
👉 No es independiente, siempre va dentro de funciones de ventana. - Pensar que PARTITION BY mejora rendimiento
👉 Es una función analítica, no un índice ni optimización.
Buenas prácticas con PARTITION BY
- Usar
PARTITION BYen reportes y análisis de datos detallados. - Siempre acompañar con
ORDER BYcuando se requiera un ranking o acumulado ordenado. - Evitar usarlo en tablas gigantes sin índices adecuados, puede ser costoso.
- Documentar qué función de ventana se aplica y sobre qué columna.
Casos de uso comunes de PARTITION BY
- Ranking de ventas por categoría
- Acumulados por cliente o departamento
- Promedios móviles por fechas
- Detección de primeros y últimos registros
- Comparación de un valor con el promedio del grupo
PARTITION BY en distintos motores de base de datos
- PostgreSQL: soporta completamente funciones de ventana con
PARTITION BY. - MySQL: desde la versión 8 soporta funciones de ventana.
- SQL Server: soporta
PARTITION BYdesde versiones antiguas. - Oracle: tiene soporte completo desde hace años.
- SQLite: soporta desde la versión 3.25.
👉 Hoy en día, prácticamente todos los motores modernos soportan PARTITION BY.
Preguntas frecuentes (FAQ)
1. ¿Puedo usar PARTITION BY sin ORDER BY?
Sí, se aplica al grupo completo sin necesidad de orden.
2. ¿Cuál es la diferencia con GROUP BY?
GROUP BY devuelve una fila por grupo; PARTITION BY conserva todas las filas.
3. ¿Puedo usar varias columnas en PARTITION BY?
Sí, por ejemplo:
PARTITION BY departamento, puesto
4. ¿Qué pasa si no incluyo PARTITION BY?
La función se aplica a todas las filas como un único grupo.
5. ¿Afecta el rendimiento?
Sí, especialmente en tablas muy grandes. Es recomendable usar índices.
Conclusión
La cláusula PARTITION BY en SQL es una herramienta poderosa para el análisis avanzado de datos:
- Permite dividir resultados en grupos sin perder detalle.
- Funciona junto a funciones de ventana como
ROW_NUMBER(),SUM(),AVG(). - Es esencial en reportes, rankings, acumulados y comparaciones.
Dominar PARTITION BY marca la diferencia entre consultas básicas y análisis avanzados en SQL.
Estudia particiones por ventana en CASE y funciones de ventana y repasa términos en el Glosario SQL completo.