El problema: filtrar por un agregado
¿Y si solo quieres las categorías con más de 2 productos, o con un precio
medio superior a 100? No puedes usar WHERE, porque WHERE mira fila a
fila, y ahí todavía no existe el agregado del grupo.
Para eso está HAVING: filtra grupos según el valor de su agregado, después
de aplicar GROUP BY.
SELECT categoria, COUNT(*) AS total
FROM productos
GROUP BY categoria
HAVING COUNT(*) > 2;
WHERE vs HAVING (la diferencia clave)
| Cláusula | Filtra... | Cuándo actúa | ¿Puede usar agregados? |
|---|---|---|---|
WHERE |
filas | antes de agrupar | No |
HAVING |
grupos | después de agrupar | Sí |
El orden lógico de ejecución es:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
Por eso puedes combinar las dos: WHERE descarta filas individuales antes de
agrupar, y HAVING descarta grupos enteros después.
-- Solo productos con stock, agrupados por categoria,
-- quedándote con las categorias cuyo precio medio supera 100
SELECT categoria, AVG(precio) AS precio_medio
FROM productos
WHERE stock > 0
GROUP BY categoria
HAVING AVG(precio) > 100
ORDER BY categoria;
Regla práctica: si la condición se puede evaluar mirando una sola fila, va en
WHERE; si necesita el resultado del grupo, va enHAVING.