← Library

Part 3 · Working with the data · 1 of 6

SQL 101: the formulas

The clause order, filters, aggregates, GROUP BY/HAVING, and joins that every exercise in this app is built from.

2 min read

The sentence

SELECT column_a, column_b        -- which columns
FROM table_name                  -- which table
WHERE condition                  -- which rows
GROUP BY column_a                -- one row per value
HAVING COUNT(*) > 1              -- filter groups
ORDER BY column_b DESC           -- sort
LIMIT 10;                        -- keep n rows

Clauses are optional but their order is fixed. Text goes in single quotes; numbers don't. ; ends the statement.

Filters

WantWrite
botha = 1 AND b = 2
eithera = 1 OR b = 2 (use parentheses with AND)
any of a liststage IN ('closed_won', 'closed_lost')
a rangeamount BETWEEN 1000 AND 5000
not equalstage <> 'closed_lost'
missingclosed_date IS NULL (never = NULL)
patternemail LIKE '%@northwind%'

Aggregates

COUNT(*), COUNT(col) (non-NULL only), SUM, AVG, MIN, MAX. Name the result: SUM(amount) AS total. In SQLite, SUM(stage = 'closed_won') counts rows where the comparison is true, and 1.0 * a / b forces decimal division.

GROUP BY / HAVING

Every SELECT column must be grouped or aggregated. WHERE filters rows before grouping; HAVING filters groups after. The duplicate idiom: GROUP BY key HAVING COUNT(*) > 1.

Joins

FROM deals d
JOIN accounts a ON a.account_id = d.account_id        -- only matches
LEFT JOIN transactions t ON t.deal_id = d.deal_id     -- all deals, NULL if none

Qualify columns after a join (d.amount). Conditions on the right-hand table of a LEFT JOIN belong in ON, not WHERE.

Dates and text (SQLite)

substr(created_date, 1, 7) → month; strftime('%Y-%W', ts) → week; julianday(b) - julianday(a) → days between.

Source: Synthesized for DPM Lab (Level 0).

Where this shows up