PROGRAMMING COURSE
One complete SQL course: querying, joins, aggregation, window functions, schema design, transactions, indexes, and the injection boundary every application crosses.
SELECT name, COUNT(*) AS orders
FROM customers
GROUP BY name
ORDER BY orders DESC;COURSE CURRICULUM
Work through a section at a time, or jump straight to the concept you need.
Explain what makes a database relational, how value matching replaces stored links, and why one set of tables can answer questions nobody planned for.
Read a table as fixed typed columns over unordered rows, and declare primary, composite, and natural keys that keep each row's identity unique.
Explain what crosses the wire when you run SQL, why a connection is a stateful session, and why each statement costs a network round trip.
Build a throwaway SQLite practice database from a seed script you can rerun at will, then verify the load with row counts before trusting any query.
You can break a SQL statement into its clauses, reformat it freely without changing its meaning, and use semicolons to mark where each statement ends.
Trace any SELECT through its real evaluation order (FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT) and predict what each clause can see.
Diagnose a failing SQL statement by reading its error message: what broke, where the parser stopped, which class of failure it is, and what to change first.
Read columns out of a table with SELECT ... FROM, and predict the exact shape of the result set before you run the query.
Write select lists that name exactly the columns you want, in the order you want them, and know why SELECT * is risky in saved queries.
Rename columns and tables inside a single query with AS, qualify columns with a short table alias, and know why WHERE cannot see a SELECT alias.
Filter a result set with WHERE so only rows whose condition is true come back, and explain why NULL rows vanish from both sides of a test.
Choose deliberately between =, <>, <, <=, >, >= knowing exactly which boundary row each keeps and how type and collation shift that boundary.
Combine WHERE conditions with AND, OR and NOT, predict which rows survive when they mix, and parenthesize to force the grouping you meant.
Filter rows against a list of values with IN and NOT IN, and predict how NULLs in the column or the list change which rows come back.
Use BETWEEN for inclusive ranges, spot reversed bounds, and switch to a half-open range when the column stores timestamps.
Filter rows by text pattern with LIKE, place % and _ where the value is unknown, and match literal wildcards using ESCAPE.
Find rows where a column holds no value using IS NULL and IS NOT NULL, and see why comparing a column to NULL with = never matches.
Write SQL comments that record the rule, ticket, or threshold behind a filter, and disable a single predicate without breaking the query.
Remove duplicate rows with SELECT DISTINCT, predict how many rows survive as you add columns, and tell real duplicates from ones a join created.
Give any query a defined row order with ORDER BY, pick ASC or DESC, sort by unselected columns, and predict where NULL rows land.
Order rows by several keys with independent ASC/DESC directions and sort on computed expressions such as totals, ratios, or cast values.
Turn a page number into a stable LIMIT/OFFSET query, spot the last page, and know when deep offsets should become keyset paging.
Write a first-n-rows query as LIMIT, TOP or FETCH FIRST, know why all three run last, and dodge Oracle's ROWNUM-before-sort trap.
Explain why a select-list alias is visible to ORDER BY but not WHERE, and filter computed values by repeating the expression or wrapping it in a CTE.
Write CASE expressions that pick a value per row, control which branch wins when conditions overlap, and decide what unmatched rows return.
Choose between CASE x WHEN v and CASE WHEN cond deliberately, and know why the simple form can never match a NULL operand.
Distinguish 0, the empty string and NULL in real data, and predict when one missing value turns a whole computed column into NULL.
Predict how =, <>, and IN behave when either side is NULL, and rewrite those comparisons with IS NULL or IS DISTINCT FROM so no rows go missing.
Predict what AND, OR and NOT return when an operand is unknown, and write filters that keep or drop NULL rows on purpose.
Audit missing data with COUNT variants, keep filter buckets summing to the row total, and write conditional counts that handle unknowns on purpose.
Use COALESCE to substitute a chosen fallback for NULL, order fallbacks by priority, and place it inside or outside an aggregate deliberately.
Guard any divisor that can be zero with NULLIF so the ratio comes back NULL for those rows instead of aborting the statement or inventing a zero.