SQL Boy
TutorialsPlayground

Format & Validate

SQL FormatterSQL MinifierSyntax Validator

Convert

JSON to SQLCSV to SQLSQL to JSONRegex to SQLExcel to SQLSQL Dialect Convertersoon

Visualize

ER Diagram GeneratorSQL Schema Diff

Generate

SQL Mock Data Generator

Analyze

SQL Query ExplainerSQL Query Analyzer

Workflow hubs

FormattingConversionSchemaAnalysis
View all tools
Daily ChallengeInterviewsCheat SheetBlog

© 2026 SQL Boy. Built for developers.

ContactPrivacyTermsAI Usage PolicyEditorial StandardsAboutRSS Feed

New conversation

What can I help with?

Ask about this page, get a hint on a challenge, or explore SQL concepts.

I know what's on this page and can give answers grounded in SQL Boy content.

Current page

Mastering Rollup Cube Grouping Sets

/blog/mastering-rollup-cube-grouping-sets

Usage status will load after login
SQL Boy
TutorialsPlayground

Format & Validate

SQL FormatterSQL MinifierSyntax Validator

Convert

JSON to SQLCSV to SQLSQL to JSONRegex to SQLExcel to SQLSQL Dialect Convertersoon

Visualize

ER Diagram GeneratorSQL Schema Diff

Generate

SQL Mock Data Generator

Analyze

SQL Query ExplainerSQL Query Analyzer

Workflow hubs

FormattingConversionSchemaAnalysis
View all tools
Daily ChallengeInterviewsCheat SheetBlog
Back to Blog
Published 2026-01-01
Updated 2026-04-20
7 min read

Mastering ROLLUP, CUBE, and GROUPING SETS in SQL

sqlanalyticsgroup-byreportingdata-warehouse

Author

SQL Boy Team

Editorial Team at SQL Boy

This article is maintained as part of SQL Boy's hands-on SQL library.

We aim to keep examples runnable, call out dialect differences, and revise unclear sections over time.

Read editorial standardsAbout SQL BoyRequest a correction

If a result or dialect note looks wrong, email [email protected] with the article URL and the section you want reviewed.

A common requirement in reporting is to show data at multiple levels of granularity: sales by region, sales by product, and a grand total of all sales.

Traditionally, you might use UNION ALL to combine three separate GROUP BY queries. This is verbose, hard to maintain, and inefficient (scanning the table three times).

Enter the SQL standard extensions for GROUP BY: ROLLUP, CUBE, and GROUPING SETS. These allow you to generate multiple levels of aggregation in a single query pass.

A Real Business Scenario: One Query for Detail Rows, Subtotals, and Grand Totals

Reporting teams often need one result set that serves several levels of a dashboard at once:

  • detail by region and product
  • subtotal by region
  • grand total for the whole business

Without grouping extensions, people often write multiple GROUP BY queries and glue them together with UNION ALL. That works, but it is verbose and easy to drift out of sync as the report evolves.

ROLLUP, CUBE, and GROUPING SETS matter because they let the database express the aggregation design directly instead of making the application reconstruct the hierarchy after the fact.

1. ROLLUP: Hierarchical Aggregation

ROLLUP is designed for hierarchical data (e.g., Year > Month > Day, or Country > State > City). It generates subtotals moving up the hierarchy.

If you group by ROLLUP(Category, Product), you get:

  1. Sales by Category and Product
  2. Sales by Category (Subtotal)
  3. Grand Total
SELECT
    COALESCE(category, 'Total') as category,
    COALESCE(product, 'All Products') as product,
    SUM(sales) as total_sales
FROM sales_data
GROUP BY ROLLUP(category, product);

(Note: COALESCE is often used to replace the NULL values generated by the rollup with readable labels like 'Total'.)

2. CUBE: All Possible Combinations

CUBE generates subtotals for every possible combination of the grouping columns. It is useful for cross-tabular reports (matrices) where there is no strict hierarchy.

If you group by CUBE(Color, Size), you get:

  1. Sales by Color and Size
  2. Sales by Color (All Sizes)
  3. Sales by Size (All Colors)
  4. Grand Total

Be careful: CUBE generates $2^N$ grouping references, so it can return a huge number of rows if you abuse it!

A Common Mistake: Replacing Every NULL with "Total" Too Early

In grouping-extension output, NULL can mean two very different things:

  • the original data actually had a null dimension value
  • the row is a subtotal or grand total produced by the grouping extension

If you blindly write:

COALESCE(category, 'Total')

you may erase that distinction and mislabel real null data as a subtotal. That is exactly why GROUPING(column) exists.

3. GROUPING SETS: Precision Control

GROUPING SETS is the most flexible. It lets you specify exactly which levels of aggregation you want.

SELECT category, product, SUM(sales)
FROM sales_data
GROUP BY GROUPING SETS (
    (category, product), -- Detailed
    (category),          -- Category Subtotals
    ()                   -- Grand Total
);

This is equivalent to ROLLUP, but you can choose to skip levels (e.g., show Grand Total and Product totals, but not Category totals).

The GROUPING() Function

When you see a NULL in a ROLLUP result, does it mean "Grand Total" or does it mean the column actually contained a null value?

The GROUPING(column) function solves this ambiguity. It returns 1 if the row is a subtotal for that column (super-aggregate) and 0 if it's a regular value.

SELECT
    CASE WHEN GROUPING(category) = 1 THEN 'Grand Total' ELSE category END as category,
    SUM(sales) as total_sales
FROM sales_data
GROUP BY ROLLUP(category);

Boundary and Performance Notes

These extensions are powerful, but they change result shape and row count in ways that reporting pipelines need to handle carefully.

  • CUBE expands quickly as dimensions increase, so the output can become much larger than expected.
  • Sorting and aggregating across multiple grouping levels can still be expensive on large fact tables.
  • Consumers of the result need a reliable way to distinguish detail rows from subtotal rows, usually with GROUPING() or explicit level labels.
  • Not every engine implements the exact same syntax or support level, so portability needs to be checked before relying on advanced grouping extensions.

In practice, GROUPING SETS is often the safest default when you know exactly which subtotal levels you need and want to avoid the combinatorial expansion of CUBE.

Interactive Playground

Note: SQLite (which powers this playground) has limited support for these extensions compared to PostgreSQL or SQL Server. However, we can simulate GROUPING SETS using UNION ALL to demonstrate the concept of multi-level aggregation.

Interactive SQL
Loading...

(Pro Tip: In reporting databases like Snowflake, BigQuery, or Postgres, always prefer the native GROUP BY ROLLUP syntax over UNION ALL for performance.)

When NOT to Use ROLLUP, CUBE, or GROUPING SETS

Avoid these extensions when:

  • the report consumer cannot distinguish subtotal rows from detail rows cleanly
  • you only need one or two simple aggregates and multiple-level output adds confusion
  • portability to engines with weak support matters more than the elegance of one native query

Sometimes two explicit grouped queries are easier to maintain than one clever result set that mixes five levels of aggregation.

Official References

  • PostgreSQL grouping sets documentation for formal ROLLUP, CUBE, and GROUPING SETS semantics.
  • SQL Server GROUP BY documentation for another major-engine implementation of advanced grouping.
  • BigQuery GROUP BY GROUPING SETS documentation for warehouse-style reporting usage.

Tool Workflow

Use tools when multi-level aggregation SQL is powerful but hard to read at report scale

ROLLUP, CUBE, and GROUPING SETS compress several report levels into one query. Use the tools to inspect the grouping structure before you rely on subtotals and grand totals in production reporting.

SQL Query Explainer

Break multi-level aggregation queries into readable clauses so subtotal logic and grouping levels are easier to verify.

Query Analysis Workflow Hub

Use the broader workflow when reporting SQL needs explanation, validation, and cleanup together.

Conclusion

Mastering these extensions separates SQL novices from professionals. They allow you to push aggregation logic down to the database layer, where it belongs, keeping your application code cleaner and your reports faster.

Related Articles

  • Mastering SQL GROUP BY: From Basics to Advanced Aggregations for the core grouping model that ROLLUP and GROUPING SETS extend.
  • How to Create Pivot Tables in SQL for another reporting pattern that turns grouped results into multi-level summaries.
  • Conditional Aggregation in SQL: A Complete Guide for the CASE-based report-building technique that often complements advanced grouping extensions.
Share this article:

Related Articles

sqlreporting

How to UNPIVOT Data in SQL with UNION ALL

Learn how to UNPIVOT wide tables into row-based data in SQL using a portable UNION ALL pattern that works well for analysis, cleanup, and reporting.

Read more
sqlanalytics

SQL Calendar Tables and Date Spines Explained

Learn when to use a SQL calendar table or date spine, how to fill missing dates safely, and why time-series reporting breaks without a complete timeline.

Read more
sqldata-warehouse

Star Schema vs. Snowflake Schema Explained

Understand the difference between star and snowflake schemas for data warehousing, and know which design best fits your analytics needs.

Read more
Previous

Solving the Gaps and Islands Problem in SQL

Next

The Power of SQL LATERAL Joins (and CROSS APPLY)

Comments

© 2026 SQL Boy. Built for developers.

ContactPrivacyTermsAI Usage PolicyEditorial StandardsAboutRSS Feed