Example 1
Get per-region, per-category, and grand-total sales in one query
CUBE(region, category) generates four grouping sets: (region, category), (region), (category), and (). The four detail rows come from the (region, category) set: East/Clothing (200), East/Electronics (500), West/Clothing (300), West/Electronics (400). The regional subtotals come from the (region) set: East sums to 700, West to 700. The category subtotals come from the (category) set: Electronics sums to 900, Clothing to 500. The grand total row comes from the () set: 1400. ORDER BY GROUPING(region), COALESCE(region, '~~~'), GROUPING(category), COALESCE(category, '~~~') places detail rows before subtotal rows within each region, and the COALESCE replaces the grouping NULL with a high-sorting sentinel so subtotals always appear after real values. Compared to ROLLUP(region, category), which would omit the per-category subtotals, CUBE is symmetric and produces every combination.
CREATE TABLE sales (
region VARCHAR(10),
category VARCHAR(15),
amount INT
);
INSERT INTO
sales
VALUES
('East', 'Electronics', 500),
('East', 'Clothing', 200),
('West', 'Electronics', 400),
('West', 'Clothing', 300);SELECT
region,
category,
SUM(amount) AS total
FROM
sales
GROUP BY
CUBE (region, category)
ORDER BY
GROUPING(region),
COALESCE(region, '~~~'),
GROUPING(category),
COALESCE(category, '~~~');| region | category | total |
|---|---|---|
| East | Clothing | 200 |
| East | Electronics | 500 |
| East | NULL | 700 |
| West | Clothing | 300 |
| West | Electronics | 400 |
| West | NULL | 700 |
| NULL | Clothing | 500 |
| NULL | Electronics | 900 |
| NULL | NULL | 1400 |
PostgreSQL and SQL Server use identical CUBE syntax and produce identical results. MySQL, MariaDB, and SQLite do not support CUBE.