[SQL] Mastering GROUP BY: Understanding ROLLUP, CUBE, and GROUPING() in Oracle SQL

 

When generating reports in Oracle SQL, one of the biggest challenges is calculating subtotals and grand totals dynamically. Manually writing multiple GROUP BY queries for different levels of aggregation can be tedious and inefficient.

Luckily, Oracle SQL provides ROLLUP and CUBE, two powerful extensions of GROUP BY that simplify multi-level aggregations. But how do you differentiate actual data rows from subtotal rows? That’s where GROUPING() comes into play!

In this blog post, we’ll explore:
ROLLUP – For hierarchical subtotals (e.g., department-wise totals).
CUBE – For all possible subtotals (e.g., department-wise and category-wise totals).
GROUPING() – To differentiate between actual data and subtotal rows.

Let’s dive into real-world examples to see how these powerful SQL features can enhance your reporting! 🚀


ROLLUP

In Oracle SQL, the ROLLUP extension is used with the GROUP BY clause to generate subtotals and a grand total in a hierarchical manner. It is useful when you need aggregate results at multiple levels of a hierarchy.

Syntax:


SELECT column1, column2, ..., aggregate_function(column_n) FROM table_name GROUP BY ROLLUP (column1, column2, ...);

The ROLLUP function creates subtotals moving from right to left, aggregating data at each level.


Example:

Let's consider a Sales table with columns department, category, and sales_amount:


SELECT department, category, SUM(sales_amount) AS total_sales FROM sales GROUP BY ROLLUP(department, category);

How It Works:

This query will return:

  1. Sales total for each (department, category).

  2. Sales subtotal for each department (NULL in the category column).

  3. A grand total for all sales (NULL in both department and category).


Example Output:




CUBE


The CUBE extension in Oracle SQL is used with the GROUP BY clause to generate all possible combinations of subtotals for the specified columns, including a grand total. Unlike ROLLUP, which creates hierarchical subtotals, CUBE computes every combination of aggregations.


Syntax:


SELECT column1, column2, ..., aggregate_function(column_n) FROM table_name GROUP BY CUBE (column1, column2, ...);

The CUBE function creates subtotal rows for every possible grouping of the specified columns.


Example:

Let's consider a Sales table with columns department, category, and sales_amount:


SELECT department, category, SUM(sales_amount) AS total_sales FROM sales GROUP BY CUBE(department, category);

How It Works:

This query will return:

  1. Sales total for each (department, category).

  2. Sales subtotal for each department (NULL in the category column).

  3. Sales subtotal for each category (NULL in the department column).

  4. A grand total (NULL in both columns).


Example Output:



Difference Between ROLLUP and CUBE

ROLLUP(col1, col2): Generates subtotals at hierarchical levels.

CUBE(col1, col2): Generates all possible combinations of subtotals.





GROUPING


The GROUPING() function helps differentiate between actual data rows and aggregated subtotal rows when using ROLLUP or CUBE. It returns:

  • 0 if the column is part of a regular row

  • 1 if the column is part of a subtotal or grand total row



Example:

Consider a Sales table with columns department, category, and sales_amount:


SELECT department, category, SUM(sales_amount) AS total_sales, GROUPING(department) AS is_dept_grouped, GROUPING(category) AS is_cat_grouped, GROUPING(department) + GROUPING(category) AS grouping_level FROM sales GROUP BY CUBE(department, category);

How It Works:

  • GROUPING(department) = 1 → Means subtotal or grand total row

  • GROUPING(category) = 1 → Means subtotal or grand total row

  • GROUPING(department) + GROUPING(category) helps classify the level of aggregation:

    • 0 → Regular data row

    • 1 → Partial subtotal (either department or category)

    • 2 → Grand total (NULL in both columns)


Example Output:



Why Use GROUPING()?

  • It helps distinguish between normal rows and subtotal rows.

  • It enables conditional formatting in reports.

  • It allows filtering only subtotal or grand total rows (HAVING GROUPING(column) = 1).



Comments

All Categories

Call Fusion BIP Report2 Change Password1 Code Combinations2 Compute Instance2 CTE1 Customer1 Data Aggregation2 Database5 Date Conversion1 DB Adapter2 Decryption1 Development1 EBS4 Encryption1 ESS Jobs3 Examine1 FBDI3 Fusion APIs1 Fusion BIP7 GIT2 GL3 GL Journals1 GL_DAILY_CONVERSION_TYPES1 GL_DAILY_RATES1 ICS1 Identity Domain1 Integrations1 Java1 Journal Import1 Keys1 Legal Entity1 LookupTypeLOV1 LOV1 LOVs1 MultiPartAPIs1 Networking1 NVL2 NVL in OIC2 OCI11 OCI Billing1 OCI Compute5 OCI Cost Management1 OCI Events Service1 OCI Free Tier3 OCI Notifification Service1 OCI Security3 OIC4 OIC Mapper2 Oracle26 Oracle ADF17 Oracle APEX1 Oracle Apps59 Oracle Apps R126 Oracle ATP1 Oracle BIP8 Oracle Cloud12 Oracle Cloud Free Tier1 Oracle cloud Infrastructure9 Oracle Cloud Security2 Oracle Cloud VM1 Oracle DB4 oracle ebs5 Oracle ERP4 Oracle ERP Adapter2 Oracle ERP Cloud7 Oracle financials2 Oracle Forms1 Oracle Fusion57 Oracle Fusion BIP4 Oracle Fusion ERP17 Oracle Fusion Financials18 Oracle Integration Cloud3 Oracle OAF17 Oracle OCI14 Oracle OIC22 Oracle SOA 12c10 Oracle SQL17 Oracle VBCS1 Oracle VBS2 Oracle Visual Builder Cloud Service1 Oracle Visual Builder Studio2 Oracle Workflow Notifications1 Others10 Payables2 Payables Import1 Properties1 R121 Register BIP as ESS Job1 Reset Password1 Responsibility1 REST4 Security List1 Site Map1 SOAP2 SOAP API2 SOAP UI3 SQL16 SQL Functions3 SQL Queries14 SQL Query8 SQL Tips3 SSH1 TCA1 Value Sets1 VBCS1 Virtual Machine2 Virtual Machines1 XML1 XSLT1
Show more