Curso de SQL completo: SELECT, JOIN, agregaciones, índices y transacciones (2026)

Las funciones de agregado resumen un conjunto de filas en un único valor. Son la base de cualquier informe o estadística: contar registros, calcular totales, promedios, valores máximos y mínimos. En SQL, las funciones de agregado operan sobre grupos de filas definidos por GROUP BY, o sobre la tabla completa si no hay GROUP BY.

En este capítulo cubrimos COUNT, SUM, AVG, MIN, MAX y cómo se comportan con valores NULL, que es la fuente de error más habitual al trabajar con agregados.

COUNT: contar filas

-- COUNT(*): cuenta todas las filas, incluidas las que tienen NULL
SELECT COUNT(*) AS total_clientes FROM clientes;

-- COUNT(columna): cuenta las filas donde esa columna NO es NULL
SELECT COUNT(ciudad) AS clientes_con_ciudad FROM clientes;
-- Si hay clientes sin ciudad (NULL), este número es menor que COUNT(*)

-- COUNT(DISTINCT columna): cuenta valores distintos no-NULL
SELECT COUNT(DISTINCT ciudad) AS ciudades_distintas FROM clientes;

-- Combinar en una sola consulta
SELECT
    COUNT(*)             AS total,
    COUNT(ciudad)        AS con_ciudad,
    COUNT(*) - COUNT(ciudad) AS sin_ciudad,
    COUNT(DISTINCT ciudad) AS ciudades_unicas
FROM clientes;

SUM: suma de valores

-- Total de stock de todos los productos
SELECT SUM(stock) AS stock_total FROM productos;

-- SUM ignora NULL (si un valor es NULL, no suma nada, no suma 0)
-- Si todos los valores son NULL, SUM devuelve NULL

-- Total facturado
SELECT SUM(total) AS facturado_total FROM pedidos WHERE estado = 'pagado';

-- Valor del inventario por categoría
SELECT
    c.nombre AS categoria,
    SUM(p.precio * p.stock) AS valor_inventario
FROM productos p
JOIN categorias c ON c.id = p.id_categoria
GROUP BY c.nombre
ORDER BY valor_inventario DESC;

AVG: promedio

-- Precio medio de los productos
SELECT ROUND(AVG(precio), 2) AS precio_medio FROM productos;

-- AVG también ignora NULL
-- CUIDADO: AVG(columna) != SUM(columna)/COUNT(*) si hay NULLs
-- AVG divide por el número de valores no-NULL; COUNT(*) cuenta todas las filas

-- Comparar precio de cada producto con el precio medio
SELECT
    nombre,
    precio,
    ROUND(AVG(precio) OVER (), 2) AS precio_medio_global,
    precio - ROUND(AVG(precio) OVER (), 2) AS diferencia
FROM productos;

MIN y MAX

-- Precio más bajo y más alto
SELECT MIN(precio) AS mas_barato, MAX(precio) AS mas_caro FROM productos;

-- Funciona con fechas: primer y último registro
SELECT MIN(fecha_alta) AS primer_cliente, MAX(fecha_alta) AS ultimo_cliente
FROM clientes;

-- Y con cadenas: orden alfabético
SELECT MIN(nombre) AS primero_abc, MAX(nombre) AS ultimo_abc FROM clientes;

-- Producto más caro (no solo el precio, sino toda la fila)
-- Subconsulta necesaria — MIN/MAX solos no devuelven la fila completa:
SELECT * FROM productos WHERE precio = (SELECT MAX(precio) FROM productos);

Valores NULL en agregados

-- Demostración del comportamiento con NULL
-- Imagina que algunos pedidos tienen total = NULL

-- COUNT(*) cuenta la fila aunque total sea NULL
SELECT COUNT(*) FROM pedidos;

-- SUM, AVG, MIN, MAX ignoran las filas donde la columna es NULL
SELECT SUM(total), AVG(total) FROM pedidos;

-- Para tratar NULL como cero en SUM:
SELECT SUM(COALESCE(total, 0)) FROM pedidos;

GROUP_CONCAT: concatenar valores de un grupo (MySQL)

-- Listar los nombres de productos de cada categoría en una sola celda
SELECT
    c.nombre AS categoria,
    GROUP_CONCAT(p.nombre ORDER BY p.nombre SEPARATOR ', ') AS productos
FROM categorias c
JOIN productos p ON p.id_categoria = c.id
GROUP BY c.nombre;

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP