Lesson 70 of 12125 min read

ROLLUP in MySQL for Subtotals and Grand Totals

Learn how ROLLUP automatically adds subtotal and grand total rows to a GROUP BY report, exactly like a spreadsheet summary.

Author: CodersNexus

ROLLUP in MySQL for Subtotals and Grand Totals

Business reports frequently need not just group-level summaries, but also subtotals and an overall grand total, exactly like a well-formatted spreadsheet with sums at the bottom of each section and a final total at the very bottom of the page. Manually writing separate queries (or a UNION of several queries) to produce this layered summary structure is tedious and error-prone. MySQL's ROLLUP extension to GROUP BY solves this directly, automatically generating these subtotal and grand total rows within a single query.

Key Definitions

  • ROLLUP: A MySQL extension to GROUP BY that adds extra summary rows representing subtotals and a grand total, in addition to the normal per-group rows.
  • Subtotal row: An extra row generated by ROLLUP representing the aggregated total for a higher-level grouping, before further breakdown by a more detailed column.
  • Grand total row: The final extra row generated by ROLLUP representing the aggregated total across the entire result set, with all grouping columns typically shown as NULL.
  • WITH ROLLUP: The MySQL syntax used to enable ROLLUP behavior at the end of a GROUP BY clause.

What You'll Learn

  • Explain what ROLLUP adds to a standard GROUP BY query.
  • Write a GROUP BY ... WITH ROLLUP query to generate subtotal and grand total rows.
  • Identify how ROLLUP represents subtotal and grand total rows using NULL placeholders.
  • Recognize realistic reporting scenarios where ROLLUP is the ideal tool.

Detailed Explanation

A standard GROUP BY query grouping by region and product_category produces one row for every unique region-category combination, and nothing more. Adding WITH ROLLUP to the end of this GROUP BY clause instructs MySQL to also compute and insert additional summary rows: one subtotal row for each region (summarizing across all its categories), and one final grand total row summarizing across the entire table.

MySQL represents these extra summary rows using NULL in the columns that no longer apply at that level of summarization. For a query grouped by region, product_category WITH ROLLUP, a subtotal row for the 'North' region would show region='North' but category=NULL, since that row represents North's total across all categories combined, not any single category. The final grand total row would show both region=NULL and category=NULL, since it summarizes across everything.

This NULL representation can initially be confusing, since it looks identical to a genuine NULL value that might exist in your actual underlying data. In practice, most reporting tools and application code handle this by using MySQL's GROUPING() function, which returns 1 specifically for these ROLLUP-generated summary rows and 0 for regular data rows, allowing you to reliably distinguish a true data NULL from a ROLLUP subtotal or grand total row, and to label these rows clearly (such as displaying 'All Categories' or 'Grand Total' instead of a raw NULL) when presenting the report to end users.

ROLLUP produces its subtotals hierarchically, following the order of columns listed in GROUP BY. Listing GROUP BY region, category WITH ROLLUP produces subtotals for each region (summarizing across its categories) and then one grand total, but reversing the column order to GROUP BY category, region WITH ROLLUP would instead produce subtotals for each category (summarizing across its regions), demonstrating that column order genuinely matters when using ROLLUP, unlike in a standard GROUP BY without ROLLUP.

Visual Summary

Draw a spreadsheet-style report with three sections: 'North' region rows for Electronics and Clothing categories, followed by a bolded subtotal row 'North - All Categories'; then 'South' region rows for Electronics and Clothing, followed by a bolded subtotal row 'South - All Categories'; and finally, at the very bottom, a bolded, larger 'GRAND TOTAL' row summarizing everything. Caption: 'ROLLUP automatically inserts subtotal and grand total rows into a single GROUP BY query's result.'

Quick Reference

regioncategorytotal_revenueRow Type
NorthElectronics5000Regular group row
NorthClothing3000Regular group row
NorthNULL8000Subtotal row (North, all categories)
SouthElectronics4200Regular group row
SouthNULL4200Subtotal row (South, all categories)
NULLNULL12200Grand total row (everything)

SQL Example

CREATE TABLE sales (
  sale_id       INT PRIMARY KEY AUTO_INCREMENT,
  region        VARCHAR(50),
  category      VARCHAR(50),
  revenue       DECIMAL(10,2)
);

INSERT INTO sales (region, category, revenue) VALUES
  ('North', 'Electronics', 5000),
  ('North', 'Clothing', 3000),
  ('South', 'Electronics', 4200);

-- GROUP BY with ROLLUP for subtotals and a grand total
SELECT
  region,
  category,
  SUM(revenue) AS total_revenue
FROM sales
GROUP BY region, category WITH ROLLUP;

-- Labeling ROLLUP rows clearly using GROUPING()
SELECT
  IF(GROUPING(region) = 1, 'All Regions', region)      AS region,
  IF(GROUPING(category) = 1, 'All Categories', category) AS category,
  SUM(revenue) AS total_revenue
FROM sales
GROUP BY region, category WITH ROLLUP;

The first query produces the raw ROLLUP output, including subtotal rows (with category shown as NULL) for each region and a final grand total row (with both region and category shown as NULL). The second query uses MySQL's GROUPING() function to detect these ROLLUP-generated rows specifically, replacing their NULL values with clear, human-readable labels like 'All Categories' and 'All Regions,' producing a much more presentable, spreadsheet-style report.

Real-World Examples

  • Financial reporting systems use ROLLUP to generate expense reports with subtotals per department and a company-wide grand total in a single query.
  • Retail sales dashboards use ROLLUP to show revenue subtotals per store region alongside an overall grand total for board-level reporting.
  • HR systems use ROLLUP to summarize headcount subtotals per department and division alongside a company-wide total headcount figure.
  • Academic administration systems use ROLLUP to report enrollment subtotals per department and an overall university-wide enrollment total.
  • Inventory systems use ROLLUP to calculate stock value subtotals per warehouse and category, alongside a grand total inventory valuation.

Common Mistakes to Avoid

  • Confusing a ROLLUP-generated NULL summary row with an actual NULL value present in the underlying data.
  • Forgetting that column order in GROUP BY affects which hierarchical level of subtotal ROLLUP produces.
  • Not using GROUPING() to clearly label ROLLUP rows, leaving confusing raw NULLs in a report meant for business users.
  • Assuming ROLLUP works identically across all database systems without checking MySQL-specific syntax and behavior.

Interview Questions

Q1. What does WITH ROLLUP add to a standard GROUP BY query?

WITH ROLLUP adds extra summary rows to the result: subtotal rows for higher-level groupings and a final grand total row summarizing the entire result set, in addition to the normal per-group rows a standard GROUP BY would produce.

Q2. How does MySQL represent subtotal and grand total rows generated by ROLLUP?

MySQL uses NULL in the grouping columns that no longer apply at that summary level. A regional subtotal row would show NULL in the category column, and the final grand total row would show NULL in every grouping column.

Q3. How can you distinguish a ROLLUP-generated NULL from an actual NULL value in your data?

Use MySQL's GROUPING() function, which returns 1 for a ROLLUP-generated summary row and 0 for a regular data row, allowing you to reliably tell the two apart and label ROLLUP rows clearly instead of showing a raw NULL.

Q4. Does the order of columns in GROUP BY matter when using ROLLUP?

Yes. ROLLUP produces subtotals hierarchically based on the order columns are listed in GROUP BY, so GROUP BY region, category WITH ROLLUP produces different subtotal levels than GROUP BY category, region WITH ROLLUP.

Practice MCQs

1. WITH ROLLUP adds which type of extra rows to a GROUP BY result?

  1. Duplicate rows only
  2. Subtotal and grand total summary rows
  3. Randomly sampled rows
  4. Rows with only NULL values and no aggregates

Answer: B. Subtotal and grand total summary rows

Explanation: ROLLUP specifically generates hierarchical subtotal rows and a final grand total row, in addition to the standard per-group rows.

2. How does MySQL represent a ROLLUP subtotal row's non-applicable grouping columns?

  1. As zero
  2. As an empty string
  3. As NULL
  4. As the word 'Total'

Answer: C. As NULL

Explanation: MySQL uses NULL to represent grouping columns that no longer apply at a given summary level, such as category being NULL in a region-level subtotal row.

3. Which function helps distinguish a ROLLUP-generated NULL from a genuine data NULL?

  1. ISNULL()
  2. GROUPING()
  3. COALESCE()
  4. IFNULL()

Answer: B. GROUPING()

Explanation: GROUPING() returns 1 specifically for ROLLUP-generated summary rows and 0 for regular rows, allowing reliable differentiation from genuine data NULLs.

4. Does the order of columns in a ROLLUP's GROUP BY clause affect the result?

  1. No, order never matters
  2. Yes, it determines the hierarchy of subtotal levels produced
  3. Only in PostgreSQL, not MySQL
  4. Only when using HAVING

Answer: B. Yes, it determines the hierarchy of subtotal levels produced

Explanation: ROLLUP generates subtotals hierarchically based on the column order in GROUP BY, so changing the order changes which level of subtotal is produced.

Quick Revision Points

  • WITH ROLLUP extends GROUP BY to automatically add subtotal and grand total rows to the result.
  • ROLLUP represents non-applicable grouping columns in summary rows using NULL.
  • GROUPING() distinguishes ROLLUP-generated NULLs (returns 1) from genuine data NULLs (returns 0).
  • The order of columns in GROUP BY determines ROLLUP's hierarchical subtotal structure.

Conclusion

  • ROLLUP eliminates the need for manual UNION-based queries to produce subtotal and grand total reports.
  • Understanding NULL as ROLLUP's summary-row indicator, and GROUPING() as the tool to detect it, is essential for correct interpretation.
  • Column order in GROUP BY directly shapes ROLLUP's subtotal hierarchy, making thoughtful column ordering important.
  • ROLLUP is a high-value, spreadsheet-style reporting tool ideal for financial, sales, and administrative summary reports.

ROLLUP is a MySQL extension to GROUP BY that automatically generates hierarchical subtotal rows and a final grand total row within a single query, mimicking the subtotal-and-total structure of a well-formatted spreadsheet report. These extra summary rows use NULL to represent grouping columns that no longer apply at that level of summarization, and MySQL's GROUPING() function reliably distinguishes these ROLLUP-generated NULLs from genuine data NULLs, allowing them to be clearly labeled for business-facing reports. The order of columns listed in GROUP BY directly determines ROLLUP's subtotal hierarchy.

Frequently Asked Questions

ROLLUP is used to automatically add subtotal rows and a grand total row to a GROUP BY query's result, similar to how a spreadsheet might show subtotals for each section followed by an overall total at the bottom.

Add WITH ROLLUP immediately after your GROUP BY column list, such as GROUP BY region, category WITH ROLLUP, which instructs MySQL to compute the extra subtotal and grand total rows alongside the normal grouped rows.

Those NULLs indicate a subtotal or grand total row generated by ROLLUP, representing a summary at a level where that particular column no longer applies, such as a region's subtotal row showing NULL for category since it summarizes across all categories.

Use MySQL's GROUPING() function on the relevant column; it returns 1 for a ROLLUP-generated summary row and 0 for a regular row, even if that regular row's actual value happens to be NULL for other reasons.

Yes. ROLLUP generates subtotals hierarchically based on the exact order of columns in your GROUP BY clause, so reordering the columns changes which level of subtotal (by region first, or by category first) gets produced.