Milestone map
Milestone map
4 milestones
Query a real database and answer a question
1–2 weeks. Finding and importing the dataset takes longer than the queries. Pick a dataset on a topic you care about — sports, music, public health, transport. The curiosity makes the queries write themselves.
Set up a local PostgreSQL or SQLite database, import a real public dataset (at least 10,000 rows), and write five queries that answer five different questions about that data. Each query must use SELECT, WHERE, and at least one aggregate function (COUNT, SUM, AVG, MIN, MAX). The questions must be ones you actually want to know the answer to — not "count all rows."
Proof required
Share a SQL file containing your five queries, each preceded by a comment stating the question it answers. Share a screenshot of each query running in a SQL client (DBeaver, TablePlus, or psql — not a browser toy) with the real result set visible. Write 150 words on one answer that surprised you — what did you expect, what did the data actually show, and what follow-up question did it make you want to ask?
What gets checked
- Five distinct queries — not five variations of SELECT * FROM table WHERE column = value
- Each query has a comment stating the specific question it answers — 'count rows' is not a question; 'which category has the most returns in Q3?' is a question
- The surprise reflection names a specific number or finding from the actual data — not a general observation about data analysis
Common mistakes
- Using a browser-based SQL toy (SQLZoo, W3Schools SQL editor) instead of a real database — the proof requires a SQL client screenshot showing a real connection, not a browser exercise
- Choosing a dataset because it's the first Google result — Kaggle has thousands of datasets on every topic; spend 30 minutes finding one you find genuinely interesting
Resources
Foundationstart here
Depthgo deeper
Masteryfor the dedicated
What a verifier looks for
- Check the SQL client screenshot — is it DBeaver, TablePlus, psql, or DataGrip? Or is it a browser editor? A real SQL client shows a connection panel on the left with tables listed. A browser toy does not.
- Read the five queries. Are they five distinct questions or five variations of the same pattern? If all five use the same aggregate function on different columns, send the submitter back.
- Ask the submitter to run a sixth query live: 'Show me the top 5 [category] by [metric] in your dataset.' If they can write it in under 2 minutes without looking anything up, M1 is real.
- Check the surprise reflection — it must name a specific number. 'I was surprised by the data' is not specific. '14% of orders were returned in December, vs 3% in other months' is specific.
Write JOIN queries across multiple tables
1–2 weeks. Schema design takes longer than the queries. The best schemas come from thinking about a real system you use — a library, a sports league, an e-commerce store, your own project's database.
Design and create a multi-table database schema for a real-world scenario you choose — not a tutorial's schema. It must have at least four tables with foreign key relationships. Import or generate realistic data (at least 1,000 rows per table). Then write five queries that each require joining at least two tables — no query can be answered from a single table.
Proof required
Share your schema as a SQL file (CREATE TABLE statements with foreign keys). Share five JOIN queries, each with a comment stating the business question. Share screenshots of each query result. Write 200 words on the difference between INNER JOIN, LEFT JOIN, and RIGHT JOIN — use an example from your own schema to illustrate when each is appropriate.
What gets checked
- Schema has genuine foreign key constraints — not just columns named user_id that aren't actually constrained
- Five queries each answer a different question requiring data from multiple tables — not five queries joining the same two tables
- The JOIN explanation uses the submitter's own schema as the example — not a generic users/orders example copied from a tutorial
Common mistakes
- Designing a schema where all the 'interesting' data is in one table and the others are lookup tables — this produces JOIN queries that are trivially simple; the schema should require JOINs to answer non-trivial questions
- Using INNER JOIN everywhere because it's the only one you know — the milestone explicitly requires understanding when LEFT JOIN is necessary, which means designing a scenario where some rows have no match
Resources
Foundationstart here
Depthgo deeper
Masteryfor the dedicated
What a verifier looks for
- Read the CREATE TABLE statements. Are foreign key constraints actually defined with REFERENCES syntax? Or are the relationships only implied by naming conventions? Actual constraints are required.
- Run one of the queries on the submitter's database with a WHERE clause that filters to zero matching rows. Does the INNER JOIN return zero rows while a LEFT JOIN would return something? If they can explain why, they understand JOINs.
- Ask: 'When would you use a LEFT JOIN instead of an INNER JOIN in your schema?' If they can point to a specific table relationship and explain the scenario (e.g. 'when I want to include customers who have no orders'), M2 is real.
- Check the JOIN explanation — it must use their schema, not a generic example. If they explain JOINs using a users/orders example that doesn't match their schema, they copied it.
Aggregate, group, and transform data with CTEs and window functions
1–2 weeks. GROUP BY is easy. Window functions take a full week to internalise. Don't rush them — every hour spent on window functions pays back tenfold in your career.
Using your Milestone 2 database, write ten queries that use GROUP BY, HAVING, subqueries, and window functions. At least two queries must use a subquery or CTE (Common Table Expression). At least two must use a window function (ROW_NUMBER, RANK, LAG, or LEAD). These are the queries that separate analysts from people who took a SQL course.
Proof required
Share all ten queries in a SQL file with comments. Share screenshots of at least five running with results. Write 250 words on the difference between WHERE and HAVING — when can you use WHERE, when must you use HAVING, and give one example from your queries where WHERE would have given the wrong answer.
What gets checked
- At least two CTEs present — not just nested subqueries; a CTE is a WITH clause that names a temporary result set
- At least two window functions present — not just aggregates; a window function uses OVER() syntax
- The WHERE vs HAVING explanation gives a concrete example where WHERE fails and HAVING is required — not just a definition of each
Common mistakes
- Using subqueries where a JOIN would be cleaner — SQL has multiple ways to express the same query; part of this milestone is developing taste for when each approach is appropriate
- Copying CTE and window function examples from a tutorial without adapting them to your schema — the verifier will ask you to write a new window function live; tutorial memorisation won't help
Resources
Foundationstart here
Depthgo deeper
Masteryfor the dedicated
What a verifier looks for
- Count the CTEs in the SQL file. A WITH clause that creates a named temporary result followed by a query that references it. If there are fewer than two, M3 is incomplete.
- Count the window functions. OVER() syntax. ROW_NUMBER() OVER(PARTITION BY ... ORDER BY ...) is the pattern. Fewer than two means M3 is incomplete.
- Ask the submitter to write a new window function live: 'Show me the running total of [metric] ordered by [date] partitioned by [category] in your schema.' If they can write it in under 5 minutes, M3 is real. If they need to look up the syntax completely, they memorised rather than understood.
- Check the WHERE vs HAVING explanation — the example must show a query where using WHERE instead of HAVING produces a wrong answer. 'HAVING filters after grouping, WHERE filters before' without an example is a definition, not understanding.
Answer a real business question end-to-end
2–3 weeks. The question definition is the hard part. Most people want to start querying immediately — resist this. Spend a full day on the three questions before touching SQL. Questions defined in advance produce better analysis than queries run to see what comes up.
Choose a real dataset you haven't used before — public data from a government open data portal, a company's public data, or a Kaggle competition dataset. Define three specific, measurable business questions before writing a single query. Write the SQL to answer all three. Present your findings as a written analysis of 300–500 words with the supporting queries and results. This is what a data analyst does on their first week at a job.
Proof required
Share a GitHub repository containing: the dataset (or a link to it), your SQL queries in a file, and a markdown file with your 300–500 word analysis. The analysis must state the three questions upfront, answer each with the query result as evidence, and conclude with one recommendation based on what the data shows. Write 150 words on what you would have done differently if you had more time or a larger dataset.
What gets checked
- Three questions are stated BEFORE the queries — not retrofitted after seeing what the data contains; the repository commit history should show the questions file committed before the SQL file
- Each answer cites the specific query result as evidence — 'the data shows X' must be followed by the number X came from
- The recommendation is actionable — 'the company should investigate Y' not 'the data is interesting'
Common mistakes
- Defining questions after exploring the data — this is data dredging, not analysis; the commit history will reveal whether questions came before or after the queries
- Analysis that only describes the data without a recommendation — description is not analysis; every finding should point toward a decision someone could make
Resources
Foundationstart here
Depthgo deeper
Masteryfor the dedicated
What a verifier looks for
- Check the repository commit history. Was the questions file committed before the SQL file? Questions-first analysis has a different commit order than data-dredging. This is the strongest signal of analytical rigour.
- Read the recommendation. Is it actionable? 'Company X should consider reviewing their Q4 discount strategy given that 34% of discounted orders were returned' is actionable. 'The data shows interesting patterns in returns' is not.
- Ask the submitter: 'If someone gave you an updated version of this dataset with 6 more months of data, which of your queries would you run first and why?' Their answer reveals whether they formed genuine hypotheses or just reported what they found.
- Check that each answer in the analysis cites a specific number from the query results. Vague references to 'the data shows' without a number mean the analysis was written before the queries were run.