Sorting, LIMIT and DISTINCT
So far, the database has decided the order of the rows in every result. It looks like they come by id, but nothing promises that: in another database, or with more data, the order can change. When you want a fixed order, add ORDER BY:
1SELECT name, price2FROM products3ORDER BY price;
| name | price |
|---|---|
| Notebook | 4.50 |
| Pens (10) | 6.00 |
| USB cable | 8.50 |
| Coffee mug | 9.90 |
| Tote bag | 11.00 |
| Water bottle | 12.00 |
| Phone case | 15.00 |
| Desk lamp | 25.00 |
| Backpack | 39.90 |
| Headphones | 59.00 |
ORDER BY
ORDER BY column sorts by that column from small to large. It goes after WHERE. Numbers compare by size, dates by earlier and later. Customers sorted by the date they joined, earliest first:
1SELECT name, joined2FROM customers3ORDER BY joined;
| name | joined |
|---|---|
| Ana Silva | 2025-01-12 |
| Ben Okafor | 2025-02-03 |
| Chloe Martin | 2025-02-20 |
| David Kim | 2025-03-15 |
| Emma Novak | 2025-04-01 |
| Farah Khan | 2025-05-18 |
| George Brown | 2025-06-09 |
| Hana Sato | 2025-07-21 |
| Ivan Petrov | 2025-08-30 |
| Julia Costa | 2025-09-14 |
Small to large is ascending, written ASC. It's what you get when you write nothing, so ORDER BY joined ASC is the same as the query above.
Large to small: DESC
Put DESC after the column name for descending order, large to small. The newest orders first:
1SELECT id, order_date, status2FROM orders3WHERE status = 'shipped'4ORDER BY order_date DESC;
| id | order_date | status |
|---|---|---|
| 11 | 2025-10-22 | shipped |
| 10 | 2025-10-20 | shipped |
| 8 | 2025-10-12 | shipped |
| 6 | 2025-10-03 | shipped |
| 5 | 2025-10-01 | shipped |
| 3 | 2025-09-18 | shipped |
| 2 | 2025-09-05 | shipped |
| 1 | 2025-09-02 | shipped |
This query first picks the shipped orders with WHERE, then sorts them. The column you sort by doesn't have to be selected either: ORDER BY stock works fine while showing only name.
How text sorts
Text can be sorted too, letter by letter from A to Z:
1SELECT name2FROM products3ORDER BY name;
| name |
|---|
| Backpack |
| Coffee mug |
| Desk lamp |
| Headphones |
| Notebook |
| Pens (10) |
| Phone case |
| Tote bag |
| USB cable |
| Water bottle |
From A to Z: the backpack comes first and the water bottle last. Capital letters or not makes no difference to the order in MySQL.
Sorting by several columns
ORDER BY can take several columns, separated by commas: rows are sorted by the first column, and rows with the same first column are sorted by the second. Each column gets its own ASC or DESC:
1SELECT name, category, price2FROM products3ORDER BY category, price DESC;
| name | category | price |
|---|---|---|
| Backpack | Bags | 39.90 |
| Tote bag | Bags | 11.00 |
| Headphones | Electronics | 59.00 |
| Desk lamp | Electronics | 25.00 |
| Phone case | Electronics | 15.00 |
| USB cable | Electronics | 8.50 |
| Water bottle | Kitchen | 12.00 |
| Coffee mug | Kitchen | 9.90 |
| Pens (10) | Stationery | 6.00 |
| Notebook | Stationery | 4.50 |
Products of the same category end up together, and within a category the priciest come first. Press Step to see ORDER BY put the rows in a new order.
Tip: When the first column has repeated values, add one more column (id, say) to fix the order; otherwise which of those rows comes first is still up to the database.
The top few: LIMIT
LIMIT 3 keeps only the first 3 rows of the result, and it goes last. Together with ORDER BY, it gives you "the top 3". The 3 priciest products:
1SELECT name, price2FROM products3ORDER BY price DESC4LIMIT 3;
| name | price |
|---|---|
| Headphones | 59.00 |
| Backpack | 39.90 |
| Desk lamp | 25.00 |
Press Step: first the rows are sorted from the highest price down, then LIMIT keeps only the first 3. LIMIT 3 without ORDER BY just means "any 3 rows", which is rarely what you want.
LIMIT is how MySQL writes it (SQLite and PostgreSQL accept it too). Other databases may write FETCH FIRST 3 ROWS ONLY (the standard way), and SQL Server writes SELECT TOP 3 ….
Which product is the result?
1SELECT name, stock2FROM products3ORDER BY stock4LIMIT 1;
ORDER BY stock with no direction sorts from small to large, so the smallest stock comes first. LIMIT 1 keeps only that first row: the desk lamp, with a stock of 0.
Dropping repeats: DISTINCT
Which cities do the customers come from? Ask for city alone and the same city shows up several times:
1SELECT city2FROM customers;
| city |
|---|
| London |
| Paris |
| London |
| Tokyo |
| Berlin |
| Paris |
| Tokyo |
| London |
| Berlin |
| Sydney |
SELECT DISTINCT keeps only one of each set of identical rows:
1SELECT DISTINCT city2FROM customers3ORDER BY city;
| city |
|---|
| Berlin |
| London |
| Paris |
| Sydney |
| Tokyo |
Five cities, each once, from Berlin to Tokyo. With several columns after DISTINCT, repeats are judged on all of them together: two rows are repeats only if every column is the same.
Practice
Write the query, then press Check. A hint costs nothing; the answer is there when you need it.
Top 3 by stock
✓Get the 3 products with the most stock, with two columns, name and stock, largest stock first.
| name | stock |
|---|---|
| USB cable | 200 |
| Notebook | 120 |
| Pens (10) | 80 |
1SELECT name, stock2FROM products;
Newest pending orders
✓Get the pending orders, with two columns, id and order_date, newest first.
| id | order_date |
|---|---|
| 12 | 2025-10-25 |
| 9 | 2025-10-15 |
| 7 | 2025-10-10 |
1SELECT id, order_date2FROM orders3ORDER BY order_date;
Customers who ordered
✓Which customer numbers appear in the orders table? Show one column, customer_id, each number once, smallest first.
| customer_id |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 7 |
| 8 |
1SELECT customer_id2FROM orders;
What you learned
- Without
ORDER BY, nothing promises the order of the rows; for a fixed order, writeORDER BY. ASCsorts small to large (and is the default),DESClarge to small; text goes A to Z, but accented letters and other scripts may not land where you expect.ORDER BY a, bsorts bya, and rows with the sameabyb; each column has its own direction.LIMIT nkeeps the first n rows, and withORDER BYgives "the top n"; other databases may writeFETCH FIRST n ROWS ONLYorTOP n.SELECT DISTINCTdrops identical rows.