Promedio ponderado en SQL

Por el equipo de promedio.net · Actualizado el

SQL no tiene una función de promedio ponderado, pero se escribe con dos sumas: SUM(valor * peso) / SUM(peso). Multiplicas cada valor por su peso, sumas esos productos y divides entre la suma de los pesos. Con GROUP BY obtienes un promedio ponderado por grupo, y con NULLIF(SUM(peso), 0) evitas el error de división entre cero.

x̄w = SUM(valor · peso)SUM(peso)

Sintaxis

SELECT grupo,
       SUM(valor * peso) / NULLIF(SUM(peso), 0) AS promedio_ponderado
FROM tabla
GROUP BY grupo;

Funciona igual en MySQL, PostgreSQL, SQL Server, Oracle y SQLite. Los pesos pueden ser créditos, unidades, horas o porcentajes; no necesitan sumar 1 ni 100, porque la división entre SUM(peso) los normaliza.

Paso a paso

  1. Identifica la columna del valor (calificación, precio) y la del peso (créditos, cantidad).
  2. Escribe SUM(valor * peso) en el numerador: la multiplicación ocurre fila por fila, antes de sumar.
  3. Escribe SUM(peso) en el denominador, envuelto en NULLIF(..., 0).
  4. Agrupa con GROUP BY si quieres un resultado por alumno, producto o periodo.
  5. Comprueba los tipos: si valor y peso son enteros, multiplica por 1.0 para no truncar.

Ejemplos resueltos

Ejemplo 1: promedio por créditos de cada alumno

CREATE TABLE kardex (
  alumno       VARCHAR(30),
  materia      VARCHAR(30),
  calificacion DECIMAL(4, 1),
  creditos     INT
);
INSERT INTO kardex VALUES
  ('Lucía', 'Cálculo',       9.0, 8),
  ('Lucía', 'Programación',  7.5, 6),
  ('Lucía', 'Inglés',        8.0, 4),
  ('Lucía', 'Ética',         6.0, 2),
  ('Mario', 'Cálculo',       7.0, 8),
  ('Mario', 'Programación',  9.5, 6),
  ('Mario', 'Inglés',       10.0, 4);

SELECT alumno,
       ROUND(SUM(calificacion * creditos) / SUM(creditos), 2) AS promedio_ponderado,
       ROUND(AVG(calificacion), 2)                            AS promedio_simple,
       SUM(creditos)                                          AS creditos
FROM kardex
GROUP BY alumno;
alumnopromedio_ponderadopromedio_simplecreditos
Lucía8.057.6320
Mario8.58.8318

Para Lucía: 9.0 × 8 + 7.5 × 6 + 8.0 × 4 + 6.0 × 2 = 161, y 161 / 20 = 8.05. Su promedio sube con la ponderación porque su mejor nota está en la materia de más créditos. A Mario le pasa lo contrario: su nota más baja, 7.0, está en Cálculo, que vale 8 créditos, y el ponderado (8.5) queda por debajo del simple (8.83).

Ejemplo 2: precio promedio de compra por producto

CREATE TABLE compras (
  producto VARCHAR(20),
  precio   DECIMAL(10, 2),
  cantidad INT
);
INSERT INTO compras VALUES
  ('Café',   180.00, 10), ('Café', 210.00, 30), ('Café', 195.00, 20),
  ('Azúcar',  32.50, 100), ('Azúcar', 35.00, 0);

SELECT producto,
       ROUND(SUM(precio * cantidad) / NULLIF(SUM(cantidad), 0), 2) AS precio_promedio,
       ROUND(AVG(precio), 2)                                      AS promedio_simple,
       SUM(cantidad)                                              AS unidades
FROM compras
GROUP BY producto;
productoprecio_promediopromedio_simpleunidades
Azúcar32.533.75100
Café200.0195.060

El café costó 12,000 en total por 60 kilos: 200 por kilo. El promedio simple de los tres precios (195) ignora que la compra más cara fue también la más grande. En el azúcar, la cotización de 35.00 con cantidad 0 no afecta al ponderado, pero sí al simple. Para este cálculo con inventarios existe la calculadora de precio promedio de compra.

Ejemplo 3: un grupo sin pesos

Si filtras solo la fila del azúcar con cantidad 0, la suma de pesos es 0:

SELECT SUM(precio * cantidad) / NULLIF(SUM(cantidad), 0) AS precio_promedio
FROM compras
WHERE cantidad = 0;

El resultado es NULL. Sin NULLIF, SQL Server y PostgreSQL lanzan un error de división entre cero, MySQL devuelve NULL con una advertencia y SQLite devuelve NULL. Con NULLIF el comportamiento es el mismo en todos: NULL indica que no hay datos para promediar.

Errores comunes

Comprueba el resultado con la calculadora de promedio ponderado. En hoja de cálculo, el equivalente es SUMAPRODUCTO, explicado en el promedio ponderado en Excel.