Contenido de esta guía
Respuesta rápida
La agregación condicional convierte una condición en un valor por fila y después agrega esos valores. Un patrón muy útil es SUM(CASE WHEN condicion THEN 1 ELSE 0 END) para contar filas que cumplen una condición.
También puedes devolver una columna numérica dentro de CASE para sumar importes únicamente cuando se cumple una condición.
Dos pasos: decidir por fila y resumir
CASEevalúa cada fila y devuelve una contribución.SUMcombina esas contribuciones en un único resultado por grupo —o en una sola fila si no existeGROUP BY.
condición por fila → CASE devuelve 1 o 0 → SUM suma los 1Esta separación evita memorizar la expresión como una receta. Primero decide qué debe aportar una fila al cálculo; después elige la agregación.
Patrones más comunes
SUM(
CASE WHEN condicion THEN 1 ELSE 0 END
) AS total_condicionSUM(
CASE WHEN condicion THEN importe ELSE 0 END
) AS importe_condicionEjemplo: varios conteos en una sola fila
Queremos obtener el total de pedidos y, en columnas separadas, cuántos están enviados, pendientes y cancelados.
SELECT COUNT(*) AS pedidos,
SUM(CASE WHEN estado = 'enviado' THEN 1 ELSE 0 END) AS enviados,
SUM(CASE WHEN estado = 'pendiente' THEN 1 ELSE 0 END) AS pendientes,
SUM(CASE WHEN estado = 'cancelado' THEN 1 ELSE 0 END) AS cancelados
FROM pedidos;| pedidos | enviados | pendientes | cancelados |
|---|---|---|---|
| 18 | 9 | 6 | 3 |
Cada pedido aporta exactamente un 1 a una de las tres sumas y 0 a las demás. Por eso 9 + 6 + 3 = 18, el mismo total que devuelve COUNT(*).
Combinarlo con GROUP BY
La misma idea funciona dentro de cada grupo. Aquí calculamos, por cliente, cuánto importe corresponde a pedidos enviados y cuánto a pendientes:
SELECT cliente_id,
COUNT(*) AS pedidos,
SUM(CASE WHEN estado = 'enviado' THEN total ELSE 0 END) AS total_enviado,
SUM(CASE WHEN estado = 'pendiente' THEN total ELSE 0 END) AS total_pendiente
FROM pedidos
GROUP BY cliente_id
ORDER BY cliente_id;Ahora cada fila representa un cliente. Dentro de ese grupo, cada CASE decide si el importe de un pedido participa en una suma concreta.
Errores frecuentes
Usar COUNT con ELSE 0
COUNT(CASE WHEN estado = 'enviado' THEN 1 ELSE 0 END)COUNT(expresion) cuenta valores no nulos. Tanto 1 como 0 son valores conocidos, así que esa expresión cuenta todas las filas. Para el patrón 1/0 usa SUM; si eliges COUNT, las filas que no cumplen deben producir NULL.
Omitir ELSE sin pensar en el conjunto vacío de coincidencias
Sin ELSE, CASE devuelve NULL cuando la condición no se cumple. Si ninguna fila aporta un valor conocido, SUM puede devolver NULL en vez de 0. Usa ELSE 0 cuando cero represente correctamente la ausencia de contribución.
Solapar categorías sin querer
Dos expresiones condicionales independientes pueden contar la misma fila si sus condiciones se superponen. Eso puede ser correcto, pero no asumas que las columnas siempre forman una partición exclusiva como en el ejemplo de estados.
Práctica guiada
Pedidos de 200 € o más
Devuelve una sola fila con dos columnas: pedidos_200_mas para pedidos cuyo total sea al menos 200 y pedidos_menos_200 para el resto.
CASE por separado.Solución razonada
SELECT
SUM(CASE WHEN total >= 200 THEN 1 ELSE 0 END) AS pedidos_200_mas,
SUM(CASE WHEN total < 200 THEN 1 ELSE 0 END) AS pedidos_menos_200
FROM pedidos;La base educativa devuelve 5 pedidos de 200 € o más y 13 por debajo de 200 €. Como las dos condiciones son excluyentes y cubren todos los totales conocidos, ambos conteos suman 18.
Compatibilidad y alternativas
El patrón combina la expresión CASE con agregados como SUM, por lo que resulta una base clara y portable para aprender agregación condicional. Algunos motores ofrecen sintaxis adicionales para filtrar la entrada de un agregado; cuando busques portabilidad entre motores, CASE permite mantener explícita la lógica de cada fila.
Qué debes recordar
CASEdecide cuánto aporta cada fila.SUMcombina esas aportaciones.SUM(CASE ... THEN 1 ELSE 0 END)cuenta condiciones.COUNT(CASE ... ELSE 0 END)no es equivalente porque 0 también es un valor no nulo.- Con
GROUP BY, la misma lógica se calcula por separado en cada grupo.