SQL · agregaciones avanzadas

GROUPING SETS, ROLLUP y CUBE: subtotales en SQL

Calcula varios niveles de agregación en una sola consulta y entiende cuándo necesitas grupos concretos, una jerarquía de subtotales o todas las combinaciones.

Lectura: 6–8 minSintaxis contrastadaPráctica con pistas
Contenido de esta guía

Respuesta rápida

GROUPING SETS permite calcular varios niveles de agrupación en una sola consulta. ROLLUP genera niveles jerárquicos y CUBE genera todas las combinaciones de las dimensiones indicadas.

GROUPING SETS
SELECT region, canal, SUM(importe) AS ventas
FROM ventas
GROUP BY GROUPING SETS (
  (region, canal),
  (region),
  ()
);

El conjunto vacío () representa el total general.

Tres herramientas, tres intenciones

FormaQué calculaUso típico
GROUPING SETSSolo los grupos que enumerasInforme con niveles concretos
ROLLUP(a,b)(a,b), (a), ()Jerarquías y subtotales
CUBE(a,b)(a,b), (a), (b), ()Análisis multidimensional

Ejemplo: detalle, subtotal por región y total

Con cuatro ventas de prueba —Norte/Web 120, Norte/Tienda 80, Sur/Web 150 y Sur/Tienda 50— el patrón produce seis filas: cuatro combinaciones, dos subtotales regionales y un total general.

ROLLUP equivalente
SELECT region, canal, SUM(importe) AS ventas
FROM ventas
GROUP BY ROLLUP (region, canal);

En PostgreSQL y SQL Server, este ROLLUP equivale a GROUPING SETS ((region, canal), (region), ()). MySQL 8.4 también documenta ROLLUP, aunque su soporte de modificadores no es idéntico al de PostgreSQL/SQL Server.

Por qué GROUPING() importa cuando hay NULL

Los motores representan con NULL las columnas que no participan en una fila de subtotal. Pero una columna de datos también puede contener un NULL real. GROUPING(columna) permite distinguir ambas situaciones en los motores que lo soportan.

Etiquetar subtotales
SELECT
  CASE WHEN GROUPING(region) = 1 THEN 'TOTAL' ELSE region END AS region,
  SUM(importe) AS ventas
FROM ventas
GROUP BY ROLLUP (region);

No uses simplemente COALESCE(region, 'TOTAL') si un NULL real en region tiene significado propio: mezclarías datos ausentes con una fila de resumen.

Compatibilidad entre motores

  • PostgreSQL: soporta GROUPING SETS, ROLLUP y CUBE.
  • SQL Server: soporta las tres formas en GROUP BY.
  • MySQL 8.4: documenta ROLLUP y GROUPING(); para combinaciones arbitrarias que no cubre su sintaxis, una alternativa explícita es UNION ALL.
  • SQLite: no ofrece estos modificadores en su GROUP BY; puedes expresar los niveles necesarios con varias agregaciones unidas mediante UNION ALL.
Alternativa portable
SELECT region, canal, SUM(importe) AS ventas
FROM ventas
GROUP BY region, canal
UNION ALL
SELECT region, NULL, SUM(importe)
FROM ventas
GROUP BY region
UNION ALL
SELECT NULL, NULL, SUM(importe)
FROM ventas;

Esta alternativa es más larga, pero hace explícitos los niveles y permite verificar el resultado en motores sin GROUPING SETS.

Práctica: total por región + total general

Intermedia · agregaciones

Elige solo dos niveles

Con la tabla ventas(region, canal, importe), devuelve un subtotal por region y una fila de total general, sin detalle por canal.

Qué debes recordar

  • GROUPING SETS calcula exactamente los niveles que enumeras.
  • ROLLUP recorre prefijos jerárquicos; CUBE genera todas las combinaciones.
  • GROUPING() distingue NULL de datos frente a NULL de subtotal.
  • La compatibilidad varía: no copies la sintaxis entre motores sin comprobarla.

Conceptos relacionados

Fuentes técnicas consultadas