Funciones de Agregación en MySQL
Aprendé a resumir y analizar grandes volúmenes de datos con COUNT, SUM, AVG, GROUP BY y más. Son las herramientas clave para generar reportes y estadísticas.
¿Qué son las funciones de agregación?
Las funciones de agregación toman un conjunto de filas y devuelven un único valor que resume ese conjunto.
A diferencia de un SELECT normal que devuelve una fila por registro,
una función de agregación devuelve una fila con el resumen de todos.
-- Sin agregación: devuelve una fila por producto
SELECT nombre, precio FROM productos;
-- Con agregación: devuelve UN SOLO valor resumen
SELECT COUNT(*) FROM productos; -- cuántos hay
SELECT AVG(precio) FROM productos; -- precio promedio
COUNT()
COUNT(*)
Cuenta la cantidad de filas
SUM()
SUM(precio)
Suma los valores de una columna
AVG()
AVG(precio)
Calcula el promedio
MIN() / MAX()
MIN(precio)
El valor mínimo o máximo
COUNT — contar registros
COUNT es la función más usada. Tiene variantes importantes:
-- COUNT(*) — cuenta TODAS las filas, incluyendo NULLs
SELECT COUNT(*) AS total_clientes FROM clientes;
-- COUNT(columna) — cuenta solo las filas donde esa columna NO es NULL
SELECT COUNT(email) AS con_email FROM clientes;
-- COUNT(DISTINCT columna) — cuenta valores únicos
SELECT COUNT(DISTINCT ciudad) AS ciudades_distintas FROM clientes;
-- Contar con condición
SELECT COUNT(*) AS pedidos_entregados
FROM ordenes
WHERE estado = 'entregado';
COUNT(*) cuenta todas las filas sin importar valores NULL. COUNT(columna) ignora las filas donde esa columna es NULL. Elegí la correcta según lo que necesitás contar.
SUM, AVG, MIN y MAX
-- Total de ventas
SELECT SUM(total) AS ventas_totales
FROM ordenes;
-- Ticket promedio por orden
SELECT ROUND(AVG(total), 2) AS ticket_promedio
FROM ordenes;
-- Producto más caro y más barato
SELECT
MAX(precio) AS precio_maximo,
MIN(precio) AS precio_minimo,
MAX(precio) - MIN(precio) AS diferencia
FROM productos;
-- Valor total del inventario (precio × stock)
SELECT ROUND(SUM(precio * stock), 2) AS valor_inventario
FROM productos;
Probá el Ejemplo 2: SUM, AVG, MIN, MAX
GROUP BY — agrupar resultados
GROUP BY divide las filas en grupos según los valores de una columna,
y aplica la función de agregación a cada grupo por separado.
Es la clave para generar reportes del tipo "totales por categoría", "ventas por mes", etc.
-- Sin GROUP BY: UN total para todos los productos
SELECT COUNT(*) AS total FROM productos; -- 29
-- Con GROUP BY: UN total POR CADA categoría
SELECT
id_categoria,
COUNT(*) AS cantidad_productos
FROM productos
GROUP BY id_categoria;
GROUP BY con JOIN para nombres descriptivos
-- En vez de mostrar el id_categoria, mostramos el nombre
SELECT
c.nombre AS categoria,
COUNT(p.id) AS cantidad_productos,
ROUND(AVG(p.precio), 2) AS precio_promedio,
MIN(p.precio) AS mas_barato,
MAX(p.precio) AS mas_caro
FROM productos p
JOIN categorias c ON p.id_categoria = c.id
GROUP BY c.id, c.nombre
ORDER BY cantidad_productos DESC;
Toda columna del SELECT que no sea una función de agregación debe aparecer en el GROUP BY. Si no, MySQL no sabe qué valor mostrar.
HAVING — filtrar grupos
WHERE filtra filas antes de agrupar.
HAVING filtra grupos después de aplicar el GROUP BY.
Se usa cuando la condición involucra una función de agregación.
-- WHERE filtra filas individuales (antes de agrupar)
SELECT ciudad, COUNT(*) AS total
FROM clientes
WHERE pais = 'Argentina' -- primero filtra por país
GROUP BY ciudad;
-- HAVING filtra grupos (después de agrupar)
SELECT ciudad, COUNT(*) AS total
FROM clientes
GROUP BY ciudad
HAVING total >= 2; -- solo ciudades con 2 o más clientes
-- Combinar ambos
SELECT
c.nombre AS categoria,
COUNT(p.id) AS cantidad,
AVG(p.precio) AS precio_prom
FROM productos p
JOIN categorias c ON p.id_categoria = c.id
WHERE p.precio > 20 -- filtra productos baratos
GROUP BY c.id, c.nombre
HAVING cantidad >= 3 -- solo categorías con 3+ productos
ORDER BY precio_prom DESC;
| WHERE | HAVING | |
|---|---|---|
| Cuándo filtra | Antes de GROUP BY | Después de GROUP BY |
| Qué filtra | Filas individuales | Grupos completos |
| Puede usar | Columnas de la tabla | Funciones de agregación |
| Ejemplo | WHERE precio > 50 | HAVING COUNT(*) > 3 |
Orden de ejecución de una query
SQL ejecuta las cláusulas en un orden específico que es importante entender para saber dónde podés usar cada cosa:
SELECT ciudad, COUNT(*) AS total -- 6. qué mostrar
FROM clientes -- 1. de qué tabla
WHERE pais = 'Argentina' -- 2. filtrar filas
GROUP BY ciudad -- 3. agrupar
HAVING total >= 2 -- 4. filtrar grupos
ORDER BY total DESC -- 5. ordenar
LIMIT 5; -- 7. limitar filas
El alias total se define en el SELECT (paso 6), pero WHERE se ejecuta en el paso 2 — antes de que el alias exista. En cambio, en HAVING (paso 4) sí podés usarlo porque el SELECT ya se procesó.
Buenas Prácticas
- Usá ROUND() con AVG para no mostrar 15 decimales:
ROUND(AVG(precio), 2) - Siempre usá alias en funciones de agregación para que el resultado sea legible
- GROUP BY todas las columnas no agregadas del SELECT — MySQL en modo estricto lo exige
- WHERE antes de GROUP BY para reducir filas antes de agrupar — es más eficiente
- HAVING solo para condiciones sobre agregaciones — si podés usar WHERE, usá WHERE