Agrupar resultados: GROUP BY y HAVING
El módulo pasado terminó con una advertencia: mezclar columnas normales con funciones de agregación necesita GROUP BY. Hoy es el protagonista. Es, para mucha gente, el concepto que más cuesta la primera vez — y el que más veces vas a usar en un trabajo real con datos.
GROUP BY: agrupar antes de agregar
GROUP BY junta las filas que comparten el mismo
valor en una columna, y a partir de ahí, cualquier función de agregación se
calcula por grupo, no sobre toda la tabla. Es la diferencia entre
"el precio medio de todo" y "el precio medio de cada categoría".
Piensa en GROUP BY como si repartieras las filas de la tabla en montoncitos de papel encima de la mesa, un montón por cada valor distinto de la columna agrupada. Después, cada función de agregación (COUNT, AVG...) mira un montón a la vez, no toda la mesa junta.
Regla de oro de GROUP BY
Toda columna que pongas en el SELECT sin envolver
en una función de agregación, tiene que estar también en el
GROUP BY. Si no, la base de datos no sabe qué valor
concreto mostrar para esa columna dentro de cada grupo.
HAVING: el WHERE de los grupos
Aquí viene la sorpresa: WHERE filtra filas
antes de agrupar, así que no puede usar el resultado de una
función de agregación (como COUNT). Para filtrar grupos ya calculados
("solo clientes con más de 2 pedidos"), necesitas
HAVING, que actúa después de
GROUP BY.
Escribir WHERE COUNT(*) > 1 en vez de
HAVING COUNT(*) > 1. La mayoría de motores te dan
un error de sintaxis directamente, porque en el momento en que se evalúa
WHERE, los grupos todavía no existen. Regla mnemotécnica: WHERE filtra filas
individuales, HAVING filtra grupos ya formados.
El orden real de ejecución (spoiler que ayuda mucho)
Escribes una consulta en el orden SELECT → FROM → WHERE →
GROUP BY → HAVING → ORDER BY, pero el motor no la ejecuta en
ese orden. Ejecuta primero FROM, luego
WHERE, luego GROUP BY,
luego HAVING, y SELECT
y ORDER BY casi al final. Entender esto es la clave
para saber por qué WHERE no puede usar alias del SELECT ni funciones de
agregación, y HAVING sí.
Ponlo a prueba
Comprueba lo que has aprendido
1. ¿Cuál es la diferencia principal entre WHERE y HAVING?
2. Si pones una columna en el SELECT sin función de agregación, ¿dónde debe estar también?
3. ¿Cuál es el orden REAL de ejecución de una consulta?