The quarterly review is tomorrow. Lena needs total revenue by region and category. The data has 600,000 rows in a database. In SQL: seven lines, three seconds. In Excel: forty minutes and a prayer that the pivot table doesn't break.
The five aggregate functions
COUNT vs COUNT(*)
COUNT(*) counts all rows including NULLs. COUNT(column) counts only non-NULL values in that column. The difference matters when your data has missing values.
COUNT(*) AS TotalRows, -- includes NULLs
COUNT(Revenue) AS RowsWithRevenue, -- excludes NULLs
COUNT(DISTINCT Salesperson) AS UniqueSalespeople
FROM SalesFact;
GROUP BY basics
Every column in SELECT that is not inside an aggregate function must appear in GROUP BY.
FROM SalesFact
GROUP BY Region
ORDER BY TotalRevenue DESC;
Multiple grouping columns
COUNT(*) AS Orders,
SUM(Revenue) AS Revenue
FROM SalesFact
GROUP BY Region, Category
ORDER BY Region, Revenue DESC;
Filtering groups with HAVING
WHERE filters individual rows before grouping. HAVING filters groups after aggregation. This distinction is critical.
FROM SalesFact
GROUP BY Salesperson
HAVING SUM(Revenue) > 5000 -- only salespeople with >5000 total
ORDER BY TotalRevenue DESC;
WHERE SUM(Revenue) > 5000 throws an error — aggregates in WHERE is always wrong. Move it to HAVING.Find every category where the average order value exceeds £300, ordered by average order value descending. Use GROUP BY, AVG(), and HAVING together. How many categories qualify?