After this lesson you can
- Sort a result set on one or more columns
- Control where NULLs land in the order
- Explain why LIMIT without ORDER BY is not reproducible
A table is a set of rows. Sets have no order. If you do not write
ORDER BY, the database is free to return rows in whatever order was
cheapest today, and that can change when the data grows or the plan
changes.
SELECT name, credit
FROM customers
ORDER BY credit DESC, name ASC;
Sorting on two columns means: by credit, highest first, and where two rows tie, by name. Without the tiebreak the order of tied rows is undefined.
Try it
CREATE TABLE customers ( id int PRIMARY KEY, name text NOT NULL, country text NOT NULL, credit int);INSERT INTO customers VALUES (1, 'Nino Beridze', 'GE', 500), (2, 'Ana Kapanadze', 'GE', 1200), (3, 'Luka Meladze', 'DE', 0), (4, 'Mari Tsiklauri', 'PL', 300), (5, 'Giorgi Abashidze', 'GE', NULL);SELECT name, creditFROM customersORDER BY credit DESC NULLS LAST, idLIMIT 3;Where NULLs go
PostgreSQL sorts NULL last when ascending and first when descending.
MySQL and SQL Server do the opposite, which is exactly the kind of
difference that bites on a migration. Say what you mean:
ORDER BY credit DESC NULLS LAST
LIMIT without ORDER BY
LIMIT 10 on its own means "any ten rows". It will look stable in
development and stop being stable in production. If you are paginating, the
order has to be deterministic, which usually means ending the sort on
something unique such as the primary key.
LIMIT is how PostgreSQL and MySQL spell it. The SQL standard writes
FETCH FIRST 10 ROWS ONLY, which PostgreSQL also accepts and MySQL
rejects; SQL Server rejects both LIMIT and that form and writes
SELECT TOP 10 ... instead.
Common mistakes
- Sorting numbers stored as text. Text sorts character by character,
so
'10'comes before'9'. Store numbers in a numeric column, or cast before sorting.
SELECT vFROM (VALUES ('9'), ('10'), ('100'), ('2')) AS t(v)ORDER BY v;- Paginating on a column that is not unique. With
ORDER BY created_atand two rows sharing a timestamp across a page boundary, one row can appear on both pages and another on neither. End the sort on a key. - Assuming
NULLS LASTis portable. PostgreSQL and Oracle accept it; MySQL and SQL Server do not, and there you sort on an expression such asCASE WHEN credit IS NULL THEN 1 ELSE 0 ENDfirst.
What interviewers ask
- Is the order of rows from
SELECTwithoutORDER BYguaranteed? No. A table is a set; the order is whatever the chosen plan produced. - How do you page through a large result reliably? A deterministic
ORDER BYending on a unique column; for deep pages, keyset pagination (WHERE (created_at, id) > (last_created_at, last_id)) instead of a bigOFFSET, which still reads every skipped row. - Where do NULLs sort? It depends on the engine — PostgreSQL treats them as larger than any value, MySQL and SQL Server as smaller — so say it explicitly.
Try it yourself
2 visible tests · 3 hidden testsTable customers(id, name, country, credit), where credit may be
NULL. Return name, country and credit for every customer, in
this order:
- by
country, A to Z; - within a country, highest
creditfirst, with aNULLcredit after every known credit; - customers who still tie, by
idascending.
The row order is part of the answer.
CREATE TABLE customers ( id int PRIMARY KEY, name text NOT NULL, country text NOT NULL, credit int);INSERT INTO customers VALUES (1, 'Nino', 'GE', 500), (2, 'Ana', 'GE', 1200), (3, 'Luka', 'DE', 0), (4, 'Mari', 'PL', 300), (5, 'Giorgi', 'GE', NULL), (6, 'Hans', 'DE', 800);Sign up to run the tests, check the hidden ones and save your progress. Sign up