Agregados y GROUP BY
FILTER, HAVING y agregados agrupados. Patrones prácticos de PostgreSQL para consultas de producción.
Receta
SELECT customer_id,
count(*) AS orders,
sum(total) AS revenue,
avg(total) FILTER (WHERE total > 100) AS avg_big_orders
FROM app.orders
GROUP BY customer_id
HAVING sum(total) > 500;Cuándo usar esto: Este patrón aparece en SQL de aplicaciones o informes que mantienes.
Ejemplo Práctico
SELECT date_trunc('day', created_at) AS day,
count(*) FILTER (WHERE email LIKE '%@example.com') AS corp_signups,
count(*) AS all_signups
FROM app.customers
GROUP BY 1
ORDER BY 1 DESC;Lo que esto demuestra:
- La cláusula
FILTERcuenta subconjuntos sinCASE HAVINGfiltra grupos después de la agregacióndate_truncagrupatimestamptzpor día
Profundización
Reglas
- Las columnas no agregadas en la lista
SELECTdeben aparecer enGROUP BY(o ser funcionalmente dependientes de la clave primaria en PG 9.1+). WHEREfiltra filas antes de agrupar;HAVINGfiltra grupos.FILTERes más limpio queSUM(CASE WHEN ...).
Trampas
SELECT *en aplicaciones - Las nuevas columnas rompen los serializadores. Solución: Enumera las columnas explícitamente.- Comparaciones
NULL-= NULLsiempre es desconocido. Solución: UsaIS NULLoIS DISTINCT FROM. - Casts implícitos - Escaneos secuenciales inesperados en tipos no coincidentes. Solución: Haz coincidir los tipos de predicado con los tipos de columna.
- Consultas sin límites - Falta
LIMITen tablas grandes. Solución: Paginación o agregación intencional. - Estadísticas obsoletas - Planes incorrectos después de una carga masiva. Solución: Ejecuta
ANALYZEen las tablas afectadas.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| ORM query builder | El equipo se estandariza en una pila | SQL complejo se vuelve opaco |
| Vista materializada | Repetir agregados costosos | Necesita estrategia de actualización |
| Réplica de almacén de datos | Escaneos pesados de BI | No para latencia OLTP |
Preguntas Frecuentes
¿Debo formatear SQL en cadenas de aplicación?
Usa cadenas de plantilla multilínea o archivos SQL; valida en CI.
¿Cuándo es `DISTINCT` suficiente?
Cuando necesitas filas únicas sin agregados.
¿`ORDER BY` perjudica a los índices?
La ordenación puede usar el orden del índice si la consulta coincide con las columnas del índice.
Relacionado
- Subconsultas y EXISTS - patrones de semi-join
- Funciones de Ventana - agregados no colapsantes
Versiones de Stack: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, y PostGIS 3.5+.