ROLLUP, CUBE e GROUPING SETS em SQLÀ medida que as necessidades de relatório crescem, o GROUP BY tradicional muitas vezes não é suficiente. Por exemplo, você pode precisar obter ao mesmo tempo:
É possível escrever várias consultas e combiná-las com UNION ALL, mas isso fica mais verboso e difícil de manter. Para esses casos, o SQL oferece extensões de agrupamento: ROLLUP, CUBE e GROUPING SETS.
Importante: nesta aula, todos os exemplos práticos usam SQL Server (AdventureWorks).
Observação de sintaxe: ROLLUP, CUBE, GROUPING SETS e GROUPING() abaixo estão no formato do SQL Server. No MySQL, a funcionalidade é mais limitada e a sintaxe é parcialmente diferente (por exemplo, é comum usar WITH ROLLUP, enquanto CUBE e GROUPING SETS podem não estar disponíveis na forma clássica).
Nesta aula, vamos ver:
ROLLUP, CUBE e GROUPING SETS se diferenciam;GROUPING().A agregação avançada ajuda a:
Considere dados de vendas na tabela SalesOrderHeader, com dimensões Status, CustomerID e métrica TotalDue.
O GROUP BY comum retorna apenas um nível de agrupamento. As extensões retornam vários níveis de uma só vez.
ROLLUP: totais hierárquicosROLLUP constrói uma hierarquia da direita para a esquerda na lista de colunas.
GROUP BY ROLLUP (col1, col2, col3)
Níveis gerados:
(col1, col2, col3) - detalhe;(col1, col2) - subtotal de col3;(col1) - subtotal de col2 e col3;() - total geral.SELECT
Status,
CustomerID,
SUM(TotalDue) AS total_amount
FROM SalesOrderHeader
GROUP BY ROLLUP (Status, CustomerID)
ORDER BY Status, CustomerID;
Resultado:
Status + CustomerID;Status;CUBE: todas as combinações de dimensõesCUBE calcula agregações para todas as combinações possíveis das colunas listadas.
GROUP BY CUBE (col1, col2)
Para duas colunas, os níveis são:
(col1, col2);(col1);(col2);().Para três colunas, já existem $2^3 = 8$ combinações, então o resultado pode crescer rapidamente.
SELECT
Status,
CustomerID,
SUM(TotalDue) AS total_amount
FROM SalesOrderHeader
GROUP BY CUBE (Status, CustomerID)
ORDER BY Status, CustomerID;
Resultado: além do detalhamento e do total geral, você também obtém:
Status;CustomerID.GROUPING SETS: controle preciso dos níveisGROUPING SETS permite declarar explicitamente apenas os níveis de agrupamento necessários.
GROUP BY GROUPING SETS (
(col1, col2),
(col1),
()
)
SELECT
Status,
CustomerID,
SUM(TotalDue) AS total_amount
FROM SalesOrderHeader
GROUP BY GROUPING SETS (
(Status, CustomerID),
(Status),
()
)
ORDER BY Status, CustomerID;
Isso é equivalente a várias consultas GROUP BY ... UNION ALL ..., mas de forma mais compacta e, em geral, melhor otimizada.
GROUPING()Nas linhas de total geradas, os valores das dimensões costumam virar NULL. O problema é que os dados originais também podem conter NULL reais.
GROUPING(column) ajuda a diferenciar:
0 - valor normal vindo dos dados;1 - valor gerado pelo nível de agregação.SELECT
Status,
CustomerID,
SUM(TotalDue) AS total_amount,
GROUPING(Status) AS g_status,
GROUPING(CustomerID) AS g_customer
FROM SalesOrderHeader
GROUP BY ROLLUP (Status, CustomerID)
ORDER BY Status, CustomerID;
Padrão prático para rotular linhas em relatórios:
CASE
WHEN GROUPING(Status) = 1 AND GROUPING(CustomerID) = 1 THEN 'GRAND TOTAL'
WHEN GROUPING(CustomerID) = 1 THEN 'STATUS SUBTOTAL'
ELSE 'DETAIL'
END AS row_type
ROLLUP quando precisar de totais hierárquicos (por exemplo, ano -> mês -> dia).CUBE quando precisar de todos os recortes analíticos entre dimensões.GROUPING SETS quando quiser controle exato sobre quais níveis retornar.CUBE pode aumentar bastante o número de linhas.DETAIL, SUBTOTAL, GRAND TOTAL) para facilitar a leitura.ORDER BY explícito para que os totais apareçam em ordem previsível.HAVING.Abaixo, um exemplo para MySQL na tabela payment, com subtotais usando WITH ROLLUP:
SELECT
staff_id,
customer_id,
SUM(amount) AS total_amount
FROM
payment
GROUP BY
staff_id, customer_id WITH ROLLUP
ORDER BY
GROUPING(staff_id),
staff_id,
GROUPING(customer_id),
customer_id;
Nesta consulta:
staff_id + customer_id;WITH ROLLUP adiciona subtotais por staff_id e um total geral;ORDER BY GROUPING(...) organiza as linhas em ordem prática: detalhes, subtotais e, por fim, total geral.Pontos importantes no MySQL:
WITH ROLLUP fornece totais hierárquicos, mas não é equivalente completo a CUBE/GROUPING SETS.UNION ALL.GROUPING(), a ordenação e a rotulagem dos totais normalmente são feitas com checagens de NULL.Relatório de soma dos pedidos por status e cliente com totais:
ROLLUP (Status, CustomerID) entrega detalhamento, subtotais por status e total geral.
Análise multidimensional de vendas:
CUBE (Status, CustomerID) entrega todas as combinações de recortes entre status e cliente.
Relatório personalizado de soma de pedidos:
GROUPING SETS permite manter apenas os níveis necessários: detalhe + subtotal do departamento + total geral.
ROLLUP, CUBE e GROUPING SETS estendem o GROUP BY tradicional.ROLLUP cria totais hierárquicos, CUBE cria todas as combinações, GROUPING SETS cria apenas os níveis explicitamente definidos.GROUPING() é essencial para interpretar corretamente linhas de total geradas.Ao dominar essas construções, você poderá criar relatórios SQL mais poderosos sem longas cadeias de UNION ALL.