HAVING: una condición para los grupos
En resumen: HAVING filtra grupos después de agrupar, WHERE filtra filas sueltas antes, y una condición sobre SUM o COUNT va en HAVING.
Problema
La tarjeta de fidelidad
La tienda lanza una tarjeta de fidelidad: los clientes con más de 3 pedidos reciben una. Sabes contar los pedidos de cada cliente con GROUP BY customer_id. Salen 18 filas. ¿Cómo conservas solo las de más de 3?
WHERE no sirve: mira pedidos sueltos, y la cuenta pertenece al cliente entero.
La idea
HAVING
HAVING es una condición para los grupos. Va después de GROUP BY y puede contener una agregación:
Cuatro clientes. Se forman los grupos, se calcula la cuenta de cada uno, y HAVING conserva solo los grupos para los que la condición es verdadera.
Pruébalo
Los pedidos grandes
Para el envío gratis necesitamos los pedidos de más de 30 €. El campo muestra el valor de cada pedido. Conserva solo los de más de 30 €.
Solución
SELECT order_id, SUM(quantity * unit_price) AS total
FROM order_items
GROUP BY order_id
HAVING SUM(quantity * unit_price) > 30;HAVING SUM(quantity * unit_price) > 30. 25 de los 60 pedidos. SQLite también acepta HAVING total > 30 con el alias, pero no todas las bases lo hacen. Ese es el tema de la próxima lección.
Míralo
SUM en WHERE
El primer intento de casi todos usa WHERE. Ejecútalo:
SQLite se detiene con «misuse of aggregate»: una agregación en un lugar donde no corresponde. En WHERE la base mira las filas una por una. Todavía no hay grupos, así que no hay nada que sumar.
La idea
WHERE y HAVING juntos
Los dos no se estorban. Trabajan en sitios distintos:
WHEREfiltra las filas antes de los grupos;HAVINGfiltra los grupos después.
La tarjeta de fidelidad sin los pedidos cancelados:
El cliente 7 se cayó. Tiene 4 pedidos, pero uno está cancelado. WHERE lo quitó antes de formar los grupos, y en su grupo quedaron 3.
Una condición que mira una fila suelta (status, una fecha, un precio) va en WHERE. Reduce las filas que la base tiene que agrupar. En HAVING deja solo las condiciones sobre agregaciones.
Pruébalo
Solo una vez
Marketing quiere escribir a los clientes que pidieron exactamente una vez en 2026. Cuenta todos los pedidos, también los cancelados. Muestra customer_id y la cantidad de sus pedidos de 2026.
Solución
SELECT customer_id, COUNT(*)
FROM orders
WHERE ordered_at >= '2026-01-01'
GROUP BY customer_id
HAVING COUNT(*) = 1;WHERE ordered_at >= '2026-01-01', luego GROUP BY customer_id y HAVING COUNT(*) = 1. Seis clientes. Los que no pidieron nada en 2026 no aparecen: no tienen filas, y por tanto tampoco grupo. Para ellos necesitarás un JOIN.
Ejercicio
Dos informes
1. Los proveedores hacen descuento en los productos que vendemos mucho. ¿Qué productos han vendido al menos 15 unidades?
Muestra product_id y las unidades vendidas de los productos con al menos 15 unidades vendidas.
Solución
SELECT product_id, SUM(quantity)
FROM order_items
GROUP BY product_id
HAVING SUM(quantity) >= 15;GROUP BY product_id HAVING SUM(quantity) >= 15. Diez productos. «Al menos 15» incluye el 15, así que es >=.
2. ¿En qué meses hubo al menos 6 pedidos? Esos meses necesitan más gente en el almacén.
Muestra el mes (año-mes) y la cantidad de pedidos de los meses con al menos 6 pedidos.
Solución
SELECT strftime('%Y-%m', ordered_at) AS month, COUNT(*)
FROM orders
GROUP BY strftime('%Y-%m', ordered_at)
HAVING COUNT(*) >= 6;GROUP BY strftime('%Y-%m', ordered_at) HAVING COUNT(*) >= 6. Cuatro meses: septiembre y octubre de 2025, mayo y septiembre de 2026. El de más movimiento es octubre de 2025, con 9 pedidos.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Aritmética en una consulta · Funciones de fecha · Funciones de agregación: COUNT, SUM, AVG · GROUP BY: un informe por grupos
- Continúa en: El orden de ejecución de una consulta · Tipos de relación: 1:1, 1:N, M:N · Claves naturales y desnormalización · Bases de datos documentales
- Ejercicios sobre el tema: Resumir