SQL GROUPING SETS, ROLLUP, and CUBE
Here's a secret that took me years to appreciate. The first time a staff engineer showed me GROUPING SETS, I'd already been writing SQL for five years and I had no idea it existed. You'll feel that same 'oh' moment today. If you've ever UNION ALL'd three copies of the same query to build a report with subtotals, you're going to love this.
Know GROUPING SETS the way the interviewer who asks it knows it.
GROUPING SETS: Pick Your Groupings
-- Profit by region, by status, and grand total
SELECT
region,
status,
SUM(profit) AS total_profit
FROM orders
GROUP BY GROUPING SETS (
(region), -- subtotal per region
(status), -- subtotal per status
() -- grand total
);Equivalent UNION ALL
-- The UNION ALL equivalent (3 scans, more code)
SELECT region, NULL AS status, SUM(profit)
FROM orders GROUP BY region
UNION ALL
SELECT NULL, status, SUM(profit)
FROM orders GROUP BY status
UNION ALL
SELECT NULL, NULL, SUM(profit)
FROM orders;ROLLUP: Hierarchical Subtotals
-- Profit with hierarchical subtotals
SELECT
year,
quarter,
month,
SUM(profit) AS total_profit
FROM orders
GROUP BY ROLLUP (year, quarter, month);
-- This generates these groupings:
-- (year, quarter, month) -> monthly detail
-- (year, quarter) -> quarterly subtotal
-- (year) -> yearly subtotal
-- () -> grand totalCache Efficiency
> The infrastructure team wants each edge location compared to the global baseline. For each edge, show its request count, its local cache-hit percentage, and the overall cache-hit percentage across all edges repeated on every row for easy comparison.
Partial ROLLUP
-- Subtotals per region, but always grouped by region
SELECT
region,
product_category,
status,
SUM(profit) AS total_profit
FROM orders
GROUP BY region, ROLLUP (product_category, status);
-- Produces per region:
-- (region, product_category, status) -> detail
-- (region, product_category) -> status subtotal
-- (region) -> region subtotalCUBE: Every Possible Combination
-- Full cross-tab: every combination of region and status
SELECT
region,
status,
SUM(profit) AS total_profit,
COUNT(*) AS num_transactions
FROM orders
GROUP BY CUBE (region, status);
-- This generates these groupings:
-- (region, status) -> detail per region + status
-- (region) -> subtotal per region
-- (status) -> subtotal per status
-- () -> grand totalROLLUP vs CUBE Comparison
| Feature | ROLLUP(a, b) | CUBE(a, b) |
|---|---|---|
| Groupings | (a,b), (a), () | (a,b), (a), (b), () |
| Count | N+1 | 2^N |
| Best for | Hierarchical dimensions (time, geography) | Cross-tab, pivot-style analysis |
| Missing grouping | (b) alone is not generated | Every combination appears |
The GROUPING() Function
SELECT
CASE
WHEN GROUPING(region) = 1 THEN 'All Regions'
ELSE region
END AS region_label,
CASE
WHEN GROUPING(status) = 1 THEN 'All Products'
ELSE status
END AS product_label,
SUM(profit) AS total_profit
FROM orders
GROUP BY CUBE (region, status)
ORDER BY
GROUPING(region),
GROUPING(status),
region,
status;GROUPING_ID() for Bitmask Identification
-- PostgreSQL: multi-column GROUPING returns a bitmask
SELECT
region,
status,
SUM(profit) AS total_profit,
GROUPING(region, status) AS grp_level
FROM orders
GROUP BY CUBE (region, status);
-- grp_level 0 = detail, 1 = status rolled up,
-- 2 = region rolled up, 3 = grand totalPractical Reporting Examples
Sales Dashboard Summary Table
This pattern materializes a summary table that a BI tool can query at any aggregation level without recomputing.
SELECT
COALESCE(region, 'ALL') AS region,
COALESCE(status, 'ALL') AS status,
SUM(profit) AS total_profit,
COUNT(*) AS num_orders,
AVG(profit) AS avg_profit,
GROUPING(region, status) AS grp_level
FROM orders
GROUP BY
GROUPING SETS (
(region, status),
(region),
(status),
()
);Monthly Retention with Subtotals
ROLLUP on cohort month and activity month gives you per-cohort retention detail plus cohort-level subtotals and a grand total.
SELECT
substr(transaction_date, 1, 7) AS txn_month,
product_id,
COUNT(DISTINCT user_id) AS active_users
FROM transactions
GROUP BY ROLLUP (substr(transaction_date, 1, 7), product_id)
ORDER BY txn_month, product_id;3 GROUPING SETS Interview Questions
Q1: Write a query that shows profit by region, profit by status, and total profit, all in one result set.
What they test: Whether you know GROUPING SETS as an alternative to UNION ALL. Most candidates write three queries. The clean answer uses GROUPING SETS. Approach: GROUP BY GROUPING SETS ((region), (status), ()). Use GROUPING() in CASE expressions to label subtotal rows. Mention it scans the table once.
Q2: Explain the difference between ROLLUP and CUBE. Give an example of when you would use each.
What they test: Conceptual clarity. They want to hear 'ROLLUP is hierarchical, CUBE is all combinations' and a concrete use case for each. Approach: ROLLUP(year, quarter, month) for time-based subtotals. CUBE(region, status) for cross-dimensional analysis. State the grouping counts: N+1 vs 2^N. Warn about CUBE on many columns.
Q3: In a ROLLUP query, how do you distinguish between a NULL that means 'subtotal' and a NULL in the actual data?
What they test: Whether you know the GROUPING() function. This separates candidates who have used ROLLUP in production from those who have only read about it. Approach: GROUPING(column) returns 1 for subtotal NULLs and 0 for real grouping values. Use it in CASE expressions or in WHERE to filter to specific aggregation levels. Mention GROUPING_ID() for multi-column bitmask identification.
Engine Support
| Engine | GROUPING SETS | ROLLUP | CUBE |
|---|---|---|---|
| PostgreSQL 9.5+ | Yes | Yes | Yes |
| SQL Server 2008+ | Yes | Yes | Yes |
| MySQL 8.0+ | No | Yes (WITH ROLLUP) | No |
| BigQuery | Yes | Yes | Yes |
| Snowflake | Yes | Yes | Yes |
| Oracle | Yes | Yes | Yes |
Frequently asked questions
What are GROUPING SETS in SQL?+
What is the difference between ROLLUP and CUBE?+
What does the GROUPING() function do?+
You're closer to fluent than you think
- 01
Active recall beats re-reading by 50%
Cognitive-science meta-reviews (Dunlosky et al., 2013) rank practice testing as a top-tier study technique, while re-reading and highlighting rank near the bottom
- 02
76% of hiring managers reject on the coding task, not the resume
From HackerRank's 2024 Developer Skills Report. Candidates who look strong on paper still fail the live screen if they haven't done timed, executable practice
- 03
Five problem shapes cover 80% of data engineer loops
Dedup, sessionization, top-N-per-group, slowly-changing dimensions, partition tricks. Writing the shapes by hand turns the unfamiliar into pattern recognition