| Lesson | Topic | Open |
|---|---|---|
| 01 | COUNT() | 01_COUNT.md |
| 02 | SUM() | 02_SUM.md |
| 03 | AVG() | 03_AVG.md |
| 04 | MIN() & MAX() | 04_MIN_MAX.md |
| 05 | GROUP BY | 05_GROUP_BY.md |
| 06 | HAVING | 06_HAVING.md |
| 07 | Conditional Aggregation | 07_CONDITIONAL_AGGREGATION.md |
| 08 | Business Cases | 08_BUSINESS_CASES.md |
Aggregation is where SQL stops answering βwhat are the rowsβ and starts answering βwhat do the rows mean.β Every dashboard tile, every KPI, every executive summary in every company that uses a relational database is, underneath, an aggregation query. This module builds that skill from COUNT(*) up to full multi-clause business reports.
Raw rows are not insight. βHere are 50,000 order recordsβ tells a business nothing actionable. βTotal revenue this month is $2.4M, up 12% from last month, driven mainly by the Nagpur regionβ β that sentence is entirely the output of SUM, GROUP BY, and comparison logic. Aggregation is the layer that turns data into decisions.
Every function in this module maps directly to a question a real business asks daily:
| Business Question | SQL Concept |
|---|---|
| βHow many customers do we have?β | COUNT() |
| βWhatβs our total revenue?β | SUM() |
| βWhatβs our average order value?β | AVG() |
| βWhat was our biggest sale? Our smallest?β | MIN() / MAX() |
| βBreak that down by region.β | GROUP BY |
| βOnly show regions above $1M.β | HAVING |
| βShow active vs. inactive counts side by side.β | Conditional Aggregation |
By the end of this module, you will be able to:
COUNT(*), COUNT(column), and COUNT(DISTINCT column)NULL behaviorMIN/MAX) across numeric, date, and text columnsGROUP BYHAVING, and know precisely when to use HAVING vs. WHERECompletion of Module 01 β Fundamentals (SELECT, WHERE, ORDER BY, JOIN basics) and familiarity with the moduleβs schema (below). No prior aggregation knowledge assumed.
| # | File | Covers |
|---|---|---|
| 01 | COUNT() | Row counting, DISTINCT, NULL behavior |
| 02 | SUM() | Totals, NULL handling, empty-group behavior |
| 03 | AVG() | Means, the βaverage of averagesβ trap |
| 04 | MIN() & MAX() | Extremes across numeric/date/text |
| 05 | GROUP BY | Per-category aggregation, the GROUP BY rule |
| 06 | HAVING | Group-level filtering, WHERE vs. HAVING |
| 07 | Conditional Aggregation | CASE WHEN inside aggregates, FILTER |
| 08 | Business Cases | Full multi-clause reports across 5 domains |
Each .md file has a matching .sql file with fully worked, business-scenario queries, expected output, and engineering notes.
COUNT() Β· COUNT(DISTINCT) Β· SUM() Β· AVG() Β· MIN() Β· MAX() Β· GROUP BY (single- and multi-column) Β· HAVING Β· CASE WHEN inside aggregates Β· PostgreSQL FILTER (WHERE ...)
employes departments locations
βββββββββββββββ βββββββββββββββ ββββββββββββββββ
β emp_id (PK) β β dept_id (PK)β β location_id β
β emp_name β β dept_name β β (PK) β
β dept_id (FK)ββββββββββββββΆβ location_id ββββββββββββΆβ city β
β manager_id β β (FK) β ββββββββββββββββ
β salary β
βββββββββββββββ
(Note: the employes spelling is used consistently across this repositoryβs seed data and is preserved here rather than βcorrected,β to avoid breaking cross-references to existing queries.)
COUNT βββΆ SUM βββΆ AVG βββΆ MIN/MAX βββΆ GROUP BY βββΆ HAVING βββΆ Conditional Aggregation βββΆ Business Cases
β β β
βββ single-value aggregates ββββββββββββββ β
per-category aggregates + filtering β
full realistic reports
This is the single most important diagram in the module β internalize it before moving on:
FROM β the base table(s) and JOINs
WHERE β filter individual ROWS (before any grouping happens)
GROUP BY β collapse rows into per-category groups
HAVING β filter GROUPS, based on aggregated values
SELECT β compute and return final columns
ORDER BY β sort the final result set
A condition on a raw column (dept_id = 10) belongs in WHERE. A condition on an aggregate result (COUNT(*) > 5) belongs in HAVING. Mixing these up is the most common aggregation bug in production SQL.
HR (headcount, payroll) Β· Workforce Planning (city/site capacity) Β· Compensation (pay-band analysis) Β· Org Design (manager span of control) Β· Executive Reporting (single-row KPI summaries) β see 08_BUSINESS_CASES.md for full worked examples in each.
SELECT ... FROM ... JOIN returns the correct rows before adding any aggregate function.GROUP BY columns.SELECT list, aliasing every one with a business-meaningful name.WHERE for row-level filters, HAVING for group-level filters β never mix the two up.ORDER BY for the audience reading the output.WHERE over HAVING whenever a condition can be expressed on raw columns β filtering rows early reduces how much data needs to be grouped and aggregated.MIN()/MAX() with no GROUP BY on an indexed column can often be answered via a single index seek rather than a full scan.COUNT(*) is not slower than COUNT(1) in any mainstream engine β this is a persistent myth. Use whichever is clearer; this repository standardizes on COUNT(*).GROUP BY at all.COUNT(column) (skips NULL) with COUNT(*) (counts every row).SUM()/AVG()/MIN()/MAX() all return NULL β not 0 β on an empty or all-NULL group.WHERE instead of HAVING.WHERE to filter to one category when the goal is to compute multiple category metrics side by side (thatβs a job for conditional aggregation).COUNT(*) alongside any AVG() so readers can judge statistical weight.HAVING thresholds and CASE WHEN boundaries as business parameters, not hardcoded literals, once a query leaves exploratory work.FROM β WHERE β GROUP BY β HAVING β SELECT β ORDER BY) well enough to place every condition in the right clause without guessing.This moduleβs .md files each end with a targeted interview-question set. The three most frequently asked aggregation interview questions, module-wide:
WHERE and HAVING?β β Covered in depth in 06_HAVING.md.COUNT(*) return 0 on an empty table, but SUM() returns NULL?β β Covered in 01_COUNT.md and 02_SUM.md.07_CONDITIONAL_AGGREGATION.md.Aggregation queries are asked in nearly every SQL technical screen, regardless of company or seniority level, because they test both syntax knowledge and the ability to translate a business question into precise, correctly-ordered SQL clauses β exactly the skill this module is built around.
4β6 hours for a first pass through all 8 files, including practice challenges.
Beginner β Intermediate (Files 01β06: Beginner. Files 07β08: Intermediate, and the natural bridge into Module 12βs advanced aggregation techniques.)
β Module 01 β Fundamentals
(Also see Module 12 β Advanced Aggregations for ROLLUP, CUBE, and GROUPING SETS, which build directly on the GROUP BY/HAVING foundation from this module, and Module 11 β NULL Handling and Data Cleaning for a deeper treatment of NULL beyond the aggregate-specific behavior covered here.)
Every diagram used across this moduleβs lessons, in one place:
| Diagram | Used In |
|---|---|
| 01_COUNT.md | |
| 02_SUM.md | |
| 03_AVG.md | |
| 04_MIN_MAX.md | |
| 05_GROUP_BY.md | |
| 06_HAVING.md | |
| 07_CONDITIONAL_AGGREGATION.md | |
| 08_BUSINESS_CASES.md |