ROLLUP adds subtotal rows to a GROUP BY:
SELECT country, city, COUNT(*) AS customers
FROM customers
GROUP BY ROLLUP (country, city);
You get one row per city, a subtotal per country (city is NULL), and a grand total (both NULL). CUBE (a, b) adds subtotals for every combination: per a, per b and overall. GROUPING SETS ((a), (b), ()) lists exactly the groupings you want.
The NULLs in subtotal rows can be confused with real NULLs in the data, such as orders with no coupon code. GROUPING(column) returns 1 on rows where that column was rolled up, so you can label them: CASE WHEN GROUPING(coupon_code) = 1 THEN 'All orders' ELSE COALESCE(coupon_code, 'no coupon') END.
PostgreSQL, SQL Server, Oracle, Snowflake and BigQuery all support these; MySQL writes GROUP BY a, b WITH ROLLUP.