Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

alias
A short second name given to a table or column in a query, so the rest of the query can refer to it briefly.
Cartesian product
Every row of one table paired with every row of another, which happens when a join has no matching rule.
column
One named field in a table, with the same kind of value in every row, such as a title or a year.
constraint
A rule a table enforces on its data, such as requiring a value or making one column unique.
distinct
A word in a query that removes repeated rows from the result, so each one appears once.
foreign key
A column that refers to the primary key of another table, so each row can be tied to one row there.
index
A stored lookup that helps the database find rows quickly without reading the whole table.
inner join
The default way of combining two tables: only pairs of rows present on both sides appear in the result.
join
A query operation that combines rows from two tables by matching values they share, usually a shared identifier.
junction table
A bridge between two tables that lets a row on either side pair with many on the other; each of its rows holds one pair.
left join
A combination that keeps every row of the first table named, filling in nulls where the second has no match.
many-to-many
A relationship where one row on each side can pair with many rows on the other, usually held in a junction table.
null
A marker for a value that is missing or unknown, which is not the same as zero or an empty string.
outer join
A join that keeps rows from one or both tables even when no row on the other side matches.
primary key
The column or columns that together identify each row uniquely, and which can never be missing.
query
A request written in SQL that asks the database for an answer, usually a table of rows.
row
One record in a table, with one value for each column that table defines.
schema
The stored plan of a database: its tables, the columns in each, and the rules those columns must follow.
table
A named set of rows that all share the same columns, such as one holding every book in a library.

SQL from the ground up

Sorting and taking the top

ORDER BY puts rows in the order you can read, LIMIT keeps only the first few, and why the two belong together whenever "the top" is what you are after.

Part 3 of 12

Beginner13 min readBack to Courses

Order decides

A query without an ORDER BY returns rows in whatever order the database finds convenient, and that order is allowed to change between runs. ORDER BY year sorts ascending — oldest first — and ORDER BY year DESC reverses it.

Sort by more than one key by listing them: ORDER BY author ASC, year DESC sorts by author, and breaks ties with the newest first. Text sorts alphabetically, numbers numerically, and each column can have its own direction.

Taking the top

LIMIT 3 keeps the first three rows of the sorted result, and LIMIT 3 OFFSET 3 skips three and takes the next three — that is how a page of results is built. OFFSET on its own is rarely useful; it is the second half of a page, not a place to start.

The order of operations matters: LIMIT throws rows away, so it must come after ORDER BY in intent as well as in the query. Limiting an unsorted result is asking for an arbitrary three rows.

Ties at the boundary are the quiet version of the same problem. If the third and fourth rows share a year, LIMIT 3 keeps whichever the database happened to reach first, and that choice can differ between runs. The tie-breaker in the next section is what makes the boundary mean something.

Where sorting happens in the query

Sorting is the step after filtering and before limiting. The database keeps the rows that pass WHERE, orders that smaller set, and only then applies LIMIT. This is why a filtered, sorted query is cheaper than sorting the whole table and throwing most of it away.

Unlike WHERE, ORDER BY can use an alias from the SELECT list because the columns already exist by the time it runs. It can also sort by an expression, such as ORDER BY length(title), though the column name is usually easier to read.

Sorting is work the database has to do

A sort is not free. If an index already holds the rows in the order you asked for, the database can read it and be done; if not, it has to compare rows and build the order itself, in memory while the set is small and in a temporary file once it is not.

EXPLAIN QUERY PLAN is how you find out which happened. It prints the steps the database intends to take, and a line about a temporary b-tree is the sign that the sort is being built from scratch. That is the first thing to look at when a query that used to be instant becomes slow, long before anyone reaches for a rewrite.

Text, numbers and dates sort differently

ORDER BY compares values by their type. Numbers sort numerically, so 9 comes before 10. Text sorts by its characters, which is why the strings '10' and '9' sort the other way round: the first character decides, and '1' is less than '9'.

The same reasoning is the argument for storing dates as YYYY-MM-DD text and quantities as numbers — the stored form and the sort order then agree, and no conversion is needed to compare them. Text also sorts by collation, so case and accents can order differently from one database to the next.

Two rows with the same sort value have no promised order between them. Add a unique tie-breaker — usually id — when the order must be stable: ORDER BY year DESC, id ASC. Pagination built on an unstable order can show the same row twice or skip one entirely.

Newest first, three at a time

SELECT title, year
FROM books
ORDER BY year DESC
LIMIT 3;

-- The next page of the same list.
SELECT title, year
FROM books
ORDER BY year DESC
LIMIT 3 OFFSET 3;

NULLs and growing pages

Where does a missing year sort? SQLite puts NULL before numbers in ascending order; PostgreSQL puts it last unless told otherwise. If the placement matters, say so explicitly with NULLS FIRST/NULLS LAST where the engine supports it, or sort on a computed flag.

OFFSET pagination gets slower and less stable as the page number grows, because the database still walks the rows it is skipping. The scalable version is a keyset query — WHERE (year, id) < (lastYear, lastId) — but ORDER BY plus LIMIT is the right first tool, and the one to understand before optimizing.

Try these next

  • Sort the books by title length, longest first, and keep the top three.
  • Add a book with a NULL year and see where it lands in ascending and descending order.
  • Build page three of the author list and compare it with LIMIT 3 OFFSET 6.

The newest five

List the five most recent books, newest first, showing their title and year.

Live Preview

A second page, with a stable tie-breaker

Sort by author alphabetically, then by year newest first, then by id. Skip the first three rows and keep the next three.

Live Preview

Sort by a column whose value is unique — an id, a title — when you care about a stable order. Two rows sharing a year can otherwise swap places from one run to the next.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What order does ORDER BY year use?