Bored Analyst
SQL

Quick Reference Cheat Sheet

Clause Execution Order

The order SQL actually runs (not the order you write it):

StepClauseWhat it does
1FROM / JOINPicks tables, joins them
2WHEREFilters rows before grouping
3GROUP BYGroups rows
4HAVINGFilters groups after aggregation
5SELECTPicks columns, computes expressions
6DISTINCTRemoves duplicates
7ORDER BYSorts results
8LIMIT / OFFSETCaps output rows

This order is why you cannot use a column alias in WHERE but can in ORDER BY.

Join Types at a Glance

JoinKeeps
INNER JOINOnly matching rows from both sides
LEFT JOINAll left rows + matching right (NULL if no match)
RIGHT JOINAll right rows + matching left (NULL if no match)
FULL OUTER JOINAll rows from both sides (NULLs where no match)
CROSS JOINEvery combination (cartesian product)
LEFT JOIN ... WHERE right.id IS NULLAnti-join: left rows with no match

Aggregate Functions

FunctionNotes
COUNT(*)Counts all rows including NULLs
COUNT(col)Counts non-NULL values in column
COUNT(DISTINCT col)Counts unique non-NULL values
SUM() / AVG()Ignores NULLs
MIN() / MAX()Works on numbers, strings, dates
STRING_AGG(col, ',')Concatenates values (Postgres)
ARRAY_AGG(col)Collects into array (Postgres)

Window Functions: The Big Five

FunctionWhat it doesGaps after ties?
ROW_NUMBER()Unique sequential number per rowN/A
RANK()Rank with gaps after tiesYes (1,1,3,4)
DENSE_RANK()Rank without gaps after tiesNo (1,1,2,3)
LAG(col, n)Value from n rows beforeN/A
LEAD(col, n)Value from n rows afterN/A
NTILE(n)Divides rows into n bucketsN/A
PERCENT_RANK()Relative rank as 0-1 decimalN/A
SUM/AVG/COUNT() OVER()Running or windowed aggregatesN/A

Common Patterns: One-Liner Reminders

PatternCore technique
Find duplicatesGROUP BY col HAVING COUNT(*) > 1
Dedup/latest per groupROW_NUMBER() OVER (PARTITION BY ... ORDER BY ... DESC) WHERE rn = 1
Running totalSUM(col) OVER (ORDER BY date_col)
Previous/next valueLAG(col) OVER (ORDER BY ...) / LEAD(col) OVER (ORDER BY ...)
Nth highest valueDENSE_RANK() OVER (ORDER BY col DESC) WHERE rank = N
Pivot rows to columnsSUM(CASE WHEN category = 'X' THEN val ELSE 0 END)
Anti-joinLEFT JOIN ... WHERE right.id IS NULL or NOT EXISTS (...)
Safe divisionx / NULLIF(y, 0)
Percent of totalval * 100.0 / SUM(val) OVER ()
Consecutive day streaksdate - ROW_NUMBER() ... OVER (ORDER BY date)

On this page