Using Advanced Grouping
1. Using GROUPING SETS
SELECT country, tier, count(*)
FROM customers
GROUP BY GROUPING SETS ((country, tier), (country), (tier), ());
| Set | Meaning |
|---|---|
| (a, b) | Group by both |
| (a) | Subtotal by a |
| () | Grand total |
2. Using ROLLUP
SELECT year, quarter, sum(revenue)
FROM sales GROUP BY ROLLUP (year, quarter);
-- Equivalent to GROUPING SETS ((year,quarter),(year),())
3. Using CUBE
SELECT region, product, sum(revenue)
FROM sales GROUP BY CUBE (region, product);
-- All 2^n combinations
| Construct | Subgroups Generated |
|---|---|
| ROLLUP(a,b,c) | n+1 levels (hierarchy) |
| CUBE(a,b,c) | 2^n combinations |
| GROUPING SETS | Explicit list |
4. Using GROUPING Function
SELECT
coalesce(country,'(all)') AS country,
coalesce(tier,'(all)') AS tier,
GROUPING(country, tier) AS gid, -- bitmask
count(*)
FROM customers GROUP BY ROLLUP (country, tier);
| GROUPING(col) Returns | Meaning |
|---|---|
| 0 | Column is in grouping set |
| 1 | Column is aggregated away (subtotal) |
5. Combining GROUPING SETS with FILTER
SELECT country, tier,
count(*) FILTER (WHERE active),
count(*) FILTER (WHERE NOT active)
FROM customers GROUP BY GROUPING SETS ((country, tier),(country),());
6. Using Empty Grouping Set
SELECT count(*) FROM orders GROUP BY GROUPING SETS (());
Note:
() in grouping sets produces a single grand-total row even when normal GROUP BY would yield none.7. Understanding GROUPING SETS vs UNION ALL
| Aspect | GROUPING SETS | UNION ALL |
|---|---|---|
| Scans | Single scan | One per query |
| Cost | Lower | Higher |
| Readability | Compact | Verbose |
8. Optimizing Advanced Grouping Queries
| Tactic | Effect |
|---|---|
| Pre-aggregate | Use materialized view for base groups |
| Indexes | BRIN/btree on group keys |
| enable_hashagg | Keep on; usually fastest |
| work_mem | Bump to avoid disk spill |
| Parallel aggregate | Enable for large fact tables |