Para obtener un promedio por categoría en SQL, combina AVG con GROUP BY: SELECT materia, AVG(calificacion) FROM calificaciones GROUP BY materia. El motor separa las filas en grupos según la columna indicada y devuelve una fila por grupo con su promedio. Toda columna del SELECT que no esté dentro de una función de agregado debe aparecer en el GROUP BY.
Sintaxis
SELECT columna_grupo, AVG(columna_valor) AS promedio
FROM tabla
[WHERE condicion_de_filas]
GROUP BY columna_grupo
[HAVING condicion_de_grupos]
[ORDER BY promedio DESC];
El orden de ejecución explica casi todos los errores: primero FROM, luego WHERE (filtra filas), después GROUP BY (forma grupos), HAVING (filtra grupos), SELECT (calcula) y al final ORDER BY.
Paso a paso
- Decide qué define un grupo: materia, sucursal, mes, cliente.
- Escribe esa columna en el
SELECTy en elGROUP BY. - Agrega
AVG(columna)con un alias claro. - Suma
COUNT(*)para saber cuántas filas respaldan cada promedio. - Ordena con
ORDER BYusando el alias.
Tabla de ejemplo:
CREATE TABLE calificaciones (
alumno VARCHAR(30),
grupo CHAR(2),
materia VARCHAR(20),
calificacion DECIMAL(4, 1)
);
INSERT INTO calificaciones VALUES
('Andrea', '3A', 'Matemáticas', 9.0),
('Andrea', '3A', 'Historia', 8.5),
('Bruno', '3A', 'Matemáticas', 6.0),
('Bruno', '3A', 'Historia', 7.5),
('Celia', '3B', 'Matemáticas', 8.0),
('Celia', '3B', 'Historia', 9.5),
('Diego', '3B', 'Matemáticas', 7.0),
('Diego', '3B', 'Historia', 6.0),
('Elena', '3B', 'Matemáticas', 10.0);
Ejemplos resueltos
Ejemplo 1: promedio por materia
SELECT materia,
ROUND(AVG(calificacion), 2) AS promedio,
COUNT(*) AS alumnos
FROM calificaciones
GROUP BY materia
ORDER BY promedio DESC;
| materia | promedio | alumnos |
|---|---|---|
| Matemáticas | 8.0 | 5 |
| Historia | 7.88 | 4 |
Historia promedia 31.5 / 4 = 7.875, que ROUND lleva a 7.88. En SQL Server verías 8.000000 y 7.880000: el promedio de un DECIMAL conserva al menos seis decimales y ROUND no los quita. Para mostrar solo dos, convierte con CAST(AVG(calificacion) AS DECIMAL(4, 2)).
Ejemplo 2: dos columnas de agrupación
SELECT grupo, materia, ROUND(AVG(calificacion), 2) AS promedio
FROM calificaciones
GROUP BY grupo, materia
ORDER BY grupo, materia;
| grupo | materia | promedio |
|---|---|---|
| 3A | Historia | 8.0 |
| 3A | Matemáticas | 7.5 |
| 3B | Historia | 7.75 |
| 3B | Matemáticas | 8.33 |
Cada combinación distinta de grupo y materia forma un grupo. Si quieres verlo como tabla cruzada (grupos en filas, materias en columnas), usa CASE dentro de AVG:
SELECT grupo,
ROUND(AVG(CASE WHEN materia = 'Matemáticas' THEN calificacion END), 2) AS matematicas,
ROUND(AVG(CASE WHEN materia = 'Historia' THEN calificacion END), 2) AS historia
FROM calificaciones
GROUP BY grupo;
| grupo | matematicas | historia |
|---|---|---|
| 3A | 7.5 | 8.0 |
| 3B | 8.33 | 7.75 |
El CASE sin ELSE devuelve NULL para las otras materias, y AVG ignora esos NULL. Con ELSE 0 el promedio saldría mal.
Ejemplo 3: promedio de filas frente a promedio de alumnos
En el grupo 3B, Elena solo tiene una calificación. Compara dos formas de calcular el promedio del grupo:
-- promedio de todas las calificaciones del grupo
SELECT grupo, ROUND(AVG(calificacion), 2) AS prom_filas
FROM calificaciones
GROUP BY grupo;
-- primero el promedio de cada alumno, luego el del grupo
SELECT grupo, ROUND(AVG(prom_alumno), 2) AS prom_de_alumnos
FROM (SELECT grupo, alumno, AVG(calificacion) AS prom_alumno
FROM calificaciones
GROUP BY grupo, alumno) t
GROUP BY grupo;
| grupo | prom_filas | prom_de_alumnos |
|---|---|---|
| 3A | 7.75 | 7.75 |
| 3B | 8.1 | 8.42 |
En 3A coinciden porque cada alumno tiene dos calificaciones. En 3B no: el primer cálculo pesa a cada alumno según cuántas calificaciones tiene; el segundo da el mismo peso a cada alumno, y el 10 de Elena cuenta como un promedio completo. Ninguno está mal, pero responden preguntas distintas.
Errores comunes
column must appear in the GROUP BY clause(PostgreSQL) ois invalid in the select list(SQL Server). Hay una columna en elSELECTque no está agrupada ni dentro de un agregado. Agrégala alGROUP BYo quítala.- Filtrar el promedio con
WHERE.WHERE AVG(...) > 8no es válido. Para filtrar grupos por su promedio se usaHAVING; lo explicamos en HAVING con AVG. - Agrupar por una columna con variantes de escritura. «Matemáticas», «matematicas» y «Matemáticas » (con espacio) forman tres grupos. Normaliza con
TRIMyLOWER, o corrige los datos. - Promediar promedios sin querer, como en el ejemplo 3. Si el resultado debe coincidir con el promedio general (7.94 en esta tabla), promedia las filas originales.
El mismo cálculo en otras herramientas: groupby en Python con pandas y PROMEDIO.SI en Excel.