Learn how SQL really runs, one idea at a time
Each lesson loads a small dataset and a query, opens the step worth looking at, says what to look for, and gives one change to try.
How a query runs
Conditions and NULL
- AND means every condition must be TRUE
- AND is evaluated before OR
- IN, LIKE and BETWEEN are ordinary conditions
- NULL is not FALSE, and it is not TRUE either
- Testing for NULL needs IS NULL
- COALESCE gives NULL a default
Computing values
Ordering and limits
- ORDER BY comes late, and ties are arbitrary
- Where NULL sorts is up to you
- LIMIT without ORDER BY is a coin flip
Joins
- INNER JOIN keeps only rows that find a partner
- LEFT JOIN keeps every left row and fills the gaps with NULL
- A join can multiply rows
- A WHERE on the right table turns LEFT JOIN into INNER JOIN
- Rows with no match: the anti-join
- Joins chain left to right, one step each
Grouping
- GROUP BY collects rows, then each group becomes one row
- Grouping by two keys
- An aggregate without GROUP BY makes one group
- count(*), count(col) and count(DISTINCT col) count different things
- WHERE filters rows, HAVING filters groups
- Finding duplicates with GROUP BY and HAVING
- DISTINCT is GROUP BY without aggregates
Composing queries
- A CTE is a named step that runs first
- A subquery that stands alone runs first
- EXISTS asks a question per row
- NOT IN with a NULL in the list keeps nothing
- UNION stacks two results
- A recursive CTE runs in rounds
Windows
- A window function looks at other rows without collapsing them
- LAG reads the previous row
- Ranking, and filtering on it with QUALIFY
- Keeping one row per group with ROW_NUMBER