SQLab Hub
Lesson 10 · ORDER BY
Lesson 10 · Fundamentals

SQL ORDER BY: ASC, DESC and Multiple Columns

ORDER BY sorts the rows of a query result. Without it, a database returns rows in whatever order is convenient for it, and that order can change. Add ORDER BY whenever the order matters: highest first, newest first, A to Z.

↕ ASC & DESC Multi-column sort ▶ Runnable Playground examples 🧪 5 practice exercises 📝 6-question quiz ⏱ ~15 min

What Does ORDER BY Do?

The most expensive products first:

SQLite · runs in the Playground
SELECT name, category, price
FROM products
ORDER BY price DESC
LIMIT 5;

▶ Run this query in the SQL Playground

Most expensive products
namecategoryprice
Single Origin Coffee 500gFood & Beverage1991.75
Succulent Plant SetHome & Garden1990.16
The Manager's PathBooks1979.28
2000A Jump Starter PackAutomotive1948.86
Japanese Green Tea 50 bagsFood & Beverage1937.51
✓ 5 rows · real output from the Playground database
SQL · syntax
SELECT columns
FROM table
ORDER BY column_1 [ASC | DESC], column_2 [ASC | DESC], ...;

ORDER BY comes at the end of the query (only LIMIT follows it) and is applied to the finished result, after WHERE, GROUP BY and HAVING.

ASC and DESC

ASC (ascending) puts the lowest value first and is the default, so ORDER BY price and ORDER BY price ASC are the same. DESC (descending) reverses it.

SQLite · runs in the Playground
SELECT name, price
FROM products
ORDER BY price
LIMIT 5;

▶ Run this query in the SQL Playground

Cheapest products first
nameprice
Sleeping Bag -10C35.76
4K Dual Dash Camera73.64
The Manager's Path89.76
Artisan Hot Sauce Trio104.33
Smart Thermostat115.69
✓ 5 rows · real output from the Playground database
TypeASCDESC
Numbers1, 2, 33, 2, 1
TextA to ZZ to A
DatesOldest firstNewest first

Sorting by Multiple Columns

List several columns and each later one breaks ties in the earlier ones. Employees by department A to Z, and within each department by salary, highest first:

SQLite · runs in the Playground
SELECT department, first_name, last_name, salary
FROM employees
ORDER BY department ASC, salary DESC
LIMIT 8;

▶ Run this query in the SQL Playground

Employees by department, then salary
departmentfirst_namelast_namesalary
Customer SuccessNancyThompson203999
Customer SuccessMariaGarcia191120
Customer SuccessBarbaraBaker188280
Customer SuccessMelissaThomas178391
Customer SuccessDorothyCampbell165118
Customer SuccessCharlesAllen162901
Customer SuccessSarahRamirez152154
Customer SuccessEdwardRamirez137737
✓ 8 rows · real output from the Playground database

Each column has its own direction. ORDER BY department, salary DESC means department ascending (the default) and salary descending; the DESC applies only to the column it follows.

Add a tie-breaker for stable results. If two rows have the same value in every ORDER BY column, the database may return them in either order, and the order can differ between runs. That matters for pagination and for "the first row". Adding a unique column such as id at the end fixes it.

Sorting Dates and Text

Dates

Newest orders first is one of the most common sorts:

SQLite · runs in the Playground
SELECT id, order_date, status, total
FROM orders
ORDER BY order_date DESC, id DESC
LIMIT 5;

▶ Run this query in the SQL Playground

Most recent orders
idorder_datestatustotal
702024-12-24pending2104.22
1712024-12-23delivered2162.1
1552024-12-19cancelled110.6
1282024-12-13refunded370.05
1692024-12-12delivered1308.16
✓ 5 rows · real output from the Playground database

In the Playground dates are stored as text in YYYY-MM-DD form, which sorts correctly as text. A format such as DD/MM/YYYY would not: "02/01/2024" would sort before "15/12/2023".

Text and upper/lower case

SQLite · runs in the Playground
SELECT DISTINCT last_name
FROM users
ORDER BY last_name
LIMIT 6;

▶ Run this query in the SQL Playground

Last names A to Z
last_name
Adams
Allen
Anderson
Baker
Brown
Campbell
✓ 6 rows · real output from the Playground database

Whether case matters depends on the database's collation. SQLite and PostgreSQL (with most collations) sort all capital letters before lowercase ones, so "Banana" comes before "apple". MySQL and SQL Server usually ignore case. To sort without regard to case everywhere, write ORDER BY LOWER(last_name).

Sorting by Aliases, Expressions and Aggregates

ORDER BY can use a column alias from SELECT, because it runs after SELECT. Here the products are sorted by their margin, a calculated column:

SQLite · runs in the Playground
SELECT name, price, cost,
       ROUND(price - cost, 2) AS margin
FROM products
ORDER BY margin DESC
LIMIT 5;

▶ Run this query in the SQL Playground

Products with the largest margin
namepricecostmargin
Succulent Plant Set1990.16616.951373.21
Single Origin Coffee 500g1991.75657.281334.47
Japanese Green Tea 50 bags1937.516201317.51
Waterproof Hiking Boots1769.01566.081202.93
Play Kitchen Deluxe1786.38589.511196.87
✓ 5 rows · real output from the Playground database

With GROUP BY, ORDER BY sorts the groups. Departments by total salary cost, highest first:

SQLite · runs in the Playground
SELECT department,
       COUNT(*) AS employees,
       SUM(salary) AS total_salary
FROM employees
GROUP BY department
ORDER BY total_salary DESC;

▶ Run this query in the SQL Playground

Departments by total salary
departmentemployeestotal_salary
Customer Success152012099
Legal161805856
Operations131649429
Marketing131613441
HR121489813
Engineering111441308
Design101339649
Sales111285822
Finance101214710
Product91072374
✓ 10 rows · real output from the Playground database

You can also sort by a column that is not in SELECT, such as SELECT first_name FROM employees ORDER BY hire_date. The exception is SELECT DISTINCT, where most databases only allow ORDER BY on the selected columns.

A custom order with CASE

SQLite · runs in the Playground
SELECT status, COUNT(*) AS orders
FROM orders
GROUP BY status
ORDER BY CASE status
           WHEN 'pending'    THEN 1
           WHEN 'processing' THEN 2
           WHEN 'shipped'    THEN 3
           WHEN 'delivered'  THEN 4
           ELSE 5
         END;

▶ Run this query in the SQL Playground

Order statuses in workflow order
statusorders
pending23
processing28
shipped21
delivered82
cancelled27
refunded19
✓ 6 rows · real output from the Playground database

Where NULLs Go

Databases disagree on where NULL sorts. SQLite, MySQL and SQL Server treat NULL as the lowest value, so NULLs come first in ascending order. PostgreSQL and Oracle treat it as the highest, so they come last:

SQLite · runs in the Playground
SELECT id, status, shipped_date
FROM orders
ORDER BY shipped_date
LIMIT 4;

▶ Run this query in the SQL Playground

Orders sorted by shipped date: NULLs first in SQLite
idstatusshipped_date
1cancelledNULL
4processingNULL
7refundedNULL
9cancelledNULL
✓ 4 rows · real output from the Playground database

SQLite (3.30+), PostgreSQL and Oracle let you choose with NULLS FIRST or NULLS LAST:

SQLite · runs in the Playground
SELECT id, status, shipped_date
FROM orders
ORDER BY shipped_date NULLS LAST
LIMIT 4;

▶ Run this query in the SQL Playground

The same sort with NULLS LAST
idstatusshipped_date
66delivered2023-01-08
196delivered2023-01-08
163shipped2023-01-09
181shipped2023-01-18
✓ 4 rows · real output from the Playground database

MySQL and SQL Server do not support NULLS LAST; sort on a flag first instead: ORDER BY shipped_date IS NULL, shipped_date.

ORDER BY and Performance

TipWhy
Sort only when you need toSorting means reading all qualifying rows before returning the first one
Use LIMIT for top-N queriesThe database can keep only the best N rows while sorting
An index on the ORDER BY columns can remove the sortRows can be read in index order
Avoid functions on the sort column when an index existsORDER BY LOWER(name) cannot use a plain index on name

See LIMIT and indexes.

Common ORDER BY Mistakes

Five errors and how to avoid them.

1. Relying on the default order

❌ Order is not guaranteed
SQL
SELECT * FROM orders LIMIT 10;
✅ Say what you want
SQL
SELECT * FROM orders
ORDER BY order_date DESC, id DESC
LIMIT 10;

Without ORDER BY, "the first 10 rows" is whatever the database finds first, and that can change after an update or on another server.

2. ORDER BY in the wrong place

❌ Syntax error
SQL
SELECT * FROM orders
ORDER BY total DESC
WHERE status = 'delivered';
✅ After WHERE, GROUP BY and HAVING
SQL
SELECT * FROM orders
WHERE status = 'delivered'
ORDER BY total DESC;

The clause order is fixed: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT.

3. Expecting DESC to apply to every column

❌ Only salary is descending
SQL
ORDER BY department, salary DESC
-- meant: both descending
✅ Direction per column
SQL
ORDER BY department DESC, salary DESC

Each column takes its own ASC or DESC; the default for the others is ASC.

4. ORDER BY column position

❌ Breaks when SELECT changes
SQL
SELECT name, price FROM products
ORDER BY 2 DESC;
✅ Use names
SQL
SELECT name, price FROM products
ORDER BY price DESC;

ORDER BY 2 means "the second selected column". Add a column at the front and the sort silently changes.

5. Sorting dates stored in the wrong format

❌ Sorts by day, not by date
SQL
-- dates stored as 'DD/MM/YYYY'
ORDER BY order_date_text
✅ ISO dates sort correctly
SQL
-- dates stored as 'YYYY-MM-DD' or a real DATE type
ORDER BY order_date

Text sorts character by character. Only year-month-day order (or a real date type) sorts chronologically.

Practice ORDER BY Queries

5 exercises on the real Playground tables.

Write each query yourself first. Every solution has been run against the Playground database.

  1. 1Easy List the 5 most recently hired employees. Table: employees

    Show solution
    SQLite · runs in the Playground
    SELECT first_name, last_name, hire_date
    FROM employees
    ORDER BY hire_date DESC
    LIMIT 5;

    ▶ Run this query in the SQL Playground

    DESC on a date puts the newest first.

  2. 2Easy List the first 6 users alphabetically by last name, then first name. Table: users

    Show solution
    SQLite · runs in the Playground
    SELECT last_name, first_name, city
    FROM users
    ORDER BY last_name, first_name
    LIMIT 6;

    ▶ Run this query in the SQL Playground

    first_name breaks ties between users with the same last name.

  3. 3Medium Show the 5 best-rated products, and among equal ratings the ones with the most reviews first. Table: products

    Show solution
    SQLite · runs in the Playground
    SELECT name, rating, review_count
    FROM products
    ORDER BY rating DESC, review_count DESC
    LIMIT 5;

    ▶ Run this query in the SQL Playground

    Two descending sorts: rating first, review_count as the tie-breaker.

  4. 4Medium Show revenue per order status, highest first. Table: orders

    Show solution
    SQLite · runs in the Playground
    SELECT status, ROUND(SUM(total), 2) AS revenue
    FROM orders
    GROUP BY status
    ORDER BY revenue DESC;

    ▶ Run this query in the SQL Playground

    ORDER BY can use the alias of the aggregate.

  5. 5Medium List 6 orders with their shipped date, showing shipped orders first (newest shipment first) and unshipped orders last. Table: orders

    Show solution
    SQLite · runs in the Playground
    SELECT id, status, shipped_date
    FROM orders
    ORDER BY shipped_date IS NULL, shipped_date DESC
    LIMIT 6;

    ▶ Run this query in the SQL Playground

    shipped_date IS NULL is 0 for shipped orders and 1 for the rest, so it sorts unshipped orders to the end in any database.

📝 Quiz — ORDER BY

Test your understanding · 0/6 answered

Question 1 of 6

What does ORDER BY do in SQL?

Question 2 of 6

What is the default direction of ORDER BY price?

Question 3 of 6

Which query shows the most expensive products first?

Question 4 of 6

What does ORDER BY salary DESC, last_name ASC do?

Question 5 of 6

Where does ORDER BY go in a query?

Question 6 of 6

Which query shows customers by total spend, highest first?

ORDER BY Interview Questions

Q1. Is the order of rows guaranteed without ORDER BY?

No. The database may return rows in any order, and it can change with indexes, updates or parallel execution. Only ORDER BY guarantees an order.

Q2. Why can ORDER BY use a SELECT alias but WHERE cannot?

ORDER BY is processed after SELECT, so the alias exists; WHERE is processed before SELECT.

Q3. Where do NULLs sort?

First in ascending order in SQLite, MySQL and SQL Server; last in PostgreSQL and Oracle. SQLite, PostgreSQL and Oracle support NULLS FIRST / NULLS LAST; MySQL and SQL Server need a trick such as ORDER BY col IS NULL, col.

Q4. How do you make pagination stable?

Sort by columns that together are unique, for example ORDER BY order_date DESC, id DESC, so rows with equal dates always come in the same order.

Q5. Does ORDER BY slow a query down?

It can, because the database has to sort all qualifying rows. An index on the sort columns, or LIMIT for top-N queries, reduces the cost.

Frequently Asked Questions

What does ORDER BY do in SQL?

ORDER BY sorts the rows of the result. By default it sorts ascending (lowest to highest, A to Z, oldest to newest). Add DESC after a column to sort descending.

Is ASC the default sort order in SQL ORDER BY?

Yes. ORDER BY column is the same as ORDER BY column ASC. You only need to write DESC when you want the highest value first.

What is the difference between ASC and DESC in ORDER BY?

ASC sorts from the lowest value to the highest: 1, 2, 3 and A, B, C. DESC reverses it. Reports often use DESC to show the top values first.

Can you ORDER BY multiple columns?

Yes. ORDER BY col1 DESC, col2 ASC sorts by col1 first and uses col2 to order rows where col1 is equal. Each column can have its own direction.

Where does ORDER BY go in the clause order?

Near the end: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, and then LIMIT. It sorts the finished result.

Can you use ORDER BY with GROUP BY?

Yes. GROUP BY builds the groups and ORDER BY sorts them, for example GROUP BY department ORDER BY SUM(salary) DESC.

Can ORDER BY use a column alias?

Yes, in all major databases. If you write SELECT SUM(total) AS revenue you can then write ORDER BY revenue DESC, because ORDER BY is processed after SELECT.

Does ORDER BY work on text columns?

Yes. ORDER BY name sorts A to Z and ORDER BY name DESC sorts Z to A. Whether upper and lower case are treated the same depends on the database's collation: SQLite and PostgreSQL usually distinguish them, MySQL and SQL Server usually do not.

Can ORDER BY sort date columns?

Yes. Dates sort like numbers: ASC is oldest first, DESC newest first. If dates are stored as text, they must be in YYYY-MM-DD form to sort correctly.

What is the difference between ORDER BY and GROUP BY?

GROUP BY combines rows into groups for aggregation and changes the number of rows. ORDER BY only rearranges rows and never changes how many there are.

How do NULL values sort in ORDER BY?

SQLite, MySQL and SQL Server put NULLs first in ascending order; PostgreSQL and Oracle put them last. SQLite, PostgreSQL and Oracle accept NULLS FIRST or NULLS LAST to choose.

Can you ORDER BY a column not in SELECT?

Yes, in most cases you can sort by any column of the tables in FROM. With SELECT DISTINCT, most databases only allow sorting by the selected columns.

Does ORDER BY affect performance?

Yes. Sorting needs all qualifying rows before the first one can be returned. An index on the ORDER BY columns can avoid the sort, and LIMIT reduces the work for top-N queries.

Can you use ORDER BY with DISTINCT?

Yes. SELECT DISTINCT last_name FROM users ORDER BY last_name works. Sort by the selected columns, because other columns are not allowed with DISTINCT in most databases.

What does ORDER BY 1 mean in SQL?

It sorts by the first column in the SELECT list. It is valid but fragile: change the SELECT list and the sort changes. Prefer column names.

How do you get the top N rows in SQL?

Combine ORDER BY with LIMIT in MySQL, PostgreSQL and SQLite: SELECT * FROM products ORDER BY price DESC LIMIT 10. SQL Server uses TOP 10, and the standard form is FETCH FIRST 10 ROWS ONLY.