Aggregation functions
Common analytics aggregations:
COUNT(*): number of rowsCOUNT(DISTINCT user_id): unique usersSUM(amount): total revenueAVG(amount): average order amountMIN(),MAX()
SELECT
COUNT(*) AS orders,
SUM(amount) AS revenue,
AVG(amount) AS avg_order_value
FROM orders;GROUP BY
Group by a dimension:
SELECT
u.country,
COUNT(*) AS orders,
SUM(o.amount) AS revenue
FROM orders o
JOIN users u ON u.user_id = o.user_id
GROUP BY u.country
ORDER BY revenue DESC;HAVING
HAVING filters groups (after aggregation).
SELECT
u.country,
COUNT(*) AS orders
FROM orders o
JOIN users u ON u.user_id = o.user_id
GROUP BY u.country
HAVING COUNT(*) >= 100
ORDER BY orders DESC;Tip: avoid common mistakes
- Every selected non-aggregated column must be in
GROUP BY. WHEREfilters rows before grouping;HAVINGfilters after.
Mental model: split → aggregate → combine
GROUP BY works the same way in every SQL dialect: rows are split into buckets by the
grouping column, an aggregate function collapses each bucket to one number, and the buckets
are combined back into a result table — one row per group.
flowchart LR
A["All rows"] --> B{"GROUP BY country"}
B --> C["Bucket: IN"]
B --> D["Bucket: US"]
C --> E["SUM(amount) per bucket"]
D --> E
E --> F["One row per group"]
Check your understanding
Which expression counts unique customers in the orders table?
COUNT(*) counts rows, while COUNT(DISTINCT user_id) counts unique users.
Show answer
B — COUNT(DISTINCT user_id) — COUNT(*) counts rows, while COUNT(DISTINCT user_id) counts unique users.
What is the difference between WHERE and HAVING?
HAVING COUNT(*) >= 100 can only be evaluated after groups exist.
Show answer
A — WHERE filters rows before grouping and HAVING filters groups after aggregation — HAVING COUNT(*) >= 100 can only be evaluated after groups exist.
In the revenue by country query, what happens if you select u.country and leave it out of GROUP BY?
Every selected non-aggregated column must be in GROUP BY, or the query is ambiguous.
Show answer
B — It breaks the rule that every non-aggregated selected column must be in GROUP BY — Every selected non-aggregated column must be in GROUP BY, or the query is ambiguous.
Which COUNT variant skips NULL values in the column?
COUNT(column) ignores NULLs, while COUNT(*) counts every row.
Show answer
C — COUNT(column) — COUNT(column) ignores NULLs, while COUNT(*) counts every row.
🧪 Try It Yourself
Exercise 1 – COUNT and SUM
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 2 – GROUP BY a dimension
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 3 – HAVING filters groups
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Next
Now that you can summarize one table, Joins (INNER, LEFT) for Analytics shows you how to bring columns from other tables into that same aggregation.