SQL ORDER BY
Without ORDER BY, a database returns rows in whatever order is cheapest for it, and that order can change from one run to the next. ORDER BY sorts the result so it is predictable: highest salary first, newest order first, names A to Z.
- Sort ascending (
ASC) and descending (DESC) - Sort by several columns to break ties
- Sort by an expression or a SELECT alias
- Control where NULLs go and define a custom order
ORDER BY syntax
SELECT columnsFROM table_nameORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...;ASC (ascending: A to Z, small to large, old to new) is the default. DESC reverses it.
Sample data
| emp_id | first_name | dept_id | salary | hire_date |
|---|---|---|---|---|
| 100 | Meera | NULL | 250000 | 2015-01-05 |
| 101 | Asha | 1 | 125000 | 2018-04-12 |
| 102 | Rahul | 1 | 98000 | 2019-07-01 |
| 103 | Priya | 1 | 72000 | 2021-01-18 |
| 104 | Karan | 1 | 72000 | 2022-08-29 |
| 105 | Vikram | 2 | 105000 | 2017-11-20 |
| 106 | Neha | 2 | 54000 | 2022-03-14 |
| 107 | Arjun | 2 | 48000 | 2023-06-05 |
| 108 | Kavya | 3 | 88000 | 2020-09-09 |
| 109 | Rohan | 3 | 45000 | 2024-01-22 |
| 110 | Sneha | 4 | 78000 | 2019-02-25 |
| 111 | Amit | 1 | 25000 | 2025-06-02 |
Sort ascending
SELECT first_name, salaryFROM employeesORDER BY salary;| first_name | salary |
|---|---|
| Amit | 25000 |
| Rohan | 45000 |
| Arjun | 48000 |
| Neha | 54000 |
| Priya | 72000 |
| Karan | 72000 |
| Sneha | 78000 |
| Kavya | 88000 |
| Rahul | 98000 |
| Vikram | 105000 |
| Asha | 125000 |
| Meera | 250000 |
FROM employeesreads 12 rows.SELECTkeeps two columns.ORDER BY salarysorts from the lowest salary (25,000) to the highest (250,000).ASCis implied.
Sort descending
SELECT first_name, hire_dateFROM employeesORDER BY hire_date DESC;| first_name | hire_date |
|---|---|
| Amit | 2025-06-02 |
| Rohan | 2024-01-22 |
| Arjun | 2023-06-05 |
| Karan | 2022-08-29 |
| Neha | 2022-03-14 |
| Priya | 2021-01-18 |
| Kavya | 2020-09-09 |
| Rahul | 2019-07-01 |
| Sneha | 2019-02-25 |
| Asha | 2018-04-12 |
| Vikram | 2017-11-20 |
| Meera | 2015-01-05 |
DESCputs the largest value first. For dates that means the most recent.- Amit, hired in June 2025, is first; Meera, hired in 2015, is last.
Sort by several columns
Sort by department, and inside each department by salary from high to low:
SELECT dept_id, first_name, salaryFROM employeesORDER BY dept_id, salary DESC;| dept_id | first_name | salary |
|---|---|---|
| NULL | Meera | 250000 |
| 1 | Asha | 125000 |
| 1 | Rahul | 98000 |
| 1 | Priya | 72000 |
| 1 | Karan | 72000 |
| 1 | Amit | 25000 |
| 2 | Vikram | 105000 |
| 2 | Neha | 54000 |
| 2 | Arjun | 48000 |
| 3 | Kavya | 88000 |
| 3 | Rohan | 45000 |
| 4 | Sneha | 78000 |
- Rows are first sorted by
dept_idascending. The CEO’s NULL department comes first, because MySQL treats NULL as smaller than any value. - Rows with the same
dept_idare then sorted bysalary DESC. - Each column has its own direction:
dept_idascending,salarydescending.
Ties are common. Priya and Karan both earn 72,000; add a second key so their order is defined:
SELECT first_name, salaryFROM employeesWHERE dept_id = 1ORDER BY salary DESC, first_name;| first_name | salary |
|---|---|
| Asha | 125000 |
| Rahul | 98000 |
| Karan | 72000 |
| Priya | 72000 |
| Amit | 25000 |
Sort by an expression or alias
ORDER BY runs after SELECT, so it can use a column alias:
SELECT first_name, salary, commission, salary + IFNULL(commission, 0) AS total_payFROM employeesWHERE dept_id = 2ORDER BY total_pay DESC;| first_name | salary | commission | total_pay |
|---|---|---|---|
| Vikram | 105000 | 12000 | 117000 |
| Neha | 54000 | 6000 | 60000 |
| Arjun | 48000 | 4500 | 52500 |
- For each Sales employee,
IFNULL(commission, 0)turns a missing commission into 0 (IFNULL). total_payadds it to the salary.ORDER BY total_pay DESCsorts by the alias, which exists becauseSELECThas already run.
You can also sort by a column that is not in the SELECT list:
SELECT product_nameFROM productsORDER BY price DESCLIMIT 3;| product_name |
|---|
| Standing Desk |
| Office Chair |
| Mechanical Keyboard |
Where do NULLs go?
MySQL sorts NULL before all values in ASC and after them in DESC. To put NULLs last in an ascending sort, sort by column IS NULL first:
SELECT first_name, commissionFROM employeesORDER BY commission IS NULL, commission;| first_name | commission |
|---|---|
| Arjun | 4500 |
| Neha | 6000 |
| Vikram | 12000 |
| Meera | NULL |
| Asha | NULL |
| Rahul | NULL |
| Priya | NULL |
| Karan | NULL |
| Kavya | NULL |
| Rohan | NULL |
| Sneha | NULL |
| Amit | NULL |
commission IS NULLis 0 for rows with a commission and 1 for rows without.- Sorting by it puts the three sales staff (0) before everyone else (1).
- Within the first group,
commissionsorts the amounts from low to high.
A custom sort order with FIELD() and CASE
Show orders by status in a business order: Pending first, then Shipped, Delivered, Cancelled:
SELECT order_id, statusFROM ordersORDER BY FIELD(status, 'Pending', 'Shipped', 'Delivered', 'Cancelled'), order_id;| order_id | status |
|---|---|
| 1008 | Pending |
| 1006 | Shipped |
| 1001 | Delivered |
| 1002 | Delivered |
| 1003 | Delivered |
| 1005 | Delivered |
| 1007 | Delivered |
| 1009 | Delivered |
| 1010 | Delivered |
| 1004 | Cancelled |
FIELD(status, ...)returns the position of the status in the list: Pending = 1, Shipped = 2, Delivered = 3, Cancelled = 4.- Sorting by that number gives the business order;
order_idbreaks ties.
FIELD() is MySQL-specific. The portable way is a CASE expression:
SELECT order_id, statusFROM ordersORDER BY CASE status WHEN 'Pending' THEN 1 WHEN 'Shipped' THEN 2 WHEN 'Delivered' THEN 3 ELSE 4 END, order_id;| order_id | status |
|---|---|
| 1008 | Pending |
| 1006 | Shipped |
| 1001 | Delivered |
| 1002 | Delivered |
| 1003 | Delivered |
| 1005 | Delivered |
| 1007 | Delivered |
| 1009 | Delivered |
| 1010 | Delivered |
| 1004 | Cancelled |
ORDER BY 2 (sorting by column position) works, but it silently changes meaning when someone edits the SELECT list. Use column names.
Exercise: Cheapest first
List product_name, category and price, sorted by category A to Z and, within a category, from the cheapest product.
| product_name | category | price |
|---|---|---|
| Wireless Mouse | Electronics | 799 |
| USB-C Hub | Electronics | 1999 |
| Mechanical Keyboard | Electronics | 3499 |
| Desk Lamp | Furniture | 1499 |
| Monitor Arm | Furniture | 2799 |
| Office Chair | Furniture | 8999 |
| Standing Desk | Furniture | 18999 |
| Gel Pens | Stationery | 199 |
| Notebook Pack | Stationery | 249 |
Hint 1
Two sort keys, both ascending.
SELECT product_name, category, priceFROM productsORDER BY category, price;| product_name | category | price |
|---|---|---|
| Wireless Mouse | Electronics | 799 |
| USB-C Hub | Electronics | 1999 |
| Mechanical Keyboard | Electronics | 3499 |
| Desk Lamp | Furniture | 1499 |
| Monitor Arm | Furniture | 2799 |
| Office Chair | Furniture | 8999 |
| Standing Desk | Furniture | 18999 |
| Gel Pens | Stationery | 199 |
| Notebook Pack | Stationery | 249 |
Exercise: Newest customers
List customers from the newest joined_on date to the oldest.
| customer_name | joined_on |
|---|---|
| Sara Thomas | 2025-03-02 |
| Manoj Pillai | 2025-01-11 |
| Ishita Bose | 2024-07-30 |
| David Fernandes | 2024-05-09 |
| Fatima Khan | 2024-03-21 |
| Rohit Kumar | 2024-02-03 |
| Ananya Sharma | 2024-01-15 |
Hint 1
Use DESC.
SELECT customer_name, joined_onFROM customersORDER BY joined_on DESC;| customer_name | joined_on |
|---|---|
| Sara Thomas | 2025-03-02 |
| Manoj Pillai | 2025-01-11 |
| Ishita Bose | 2024-07-30 |
| David Fernandes | 2024-05-09 |
| Fatima Khan | 2024-03-21 |
| Rohit Kumar | 2024-02-03 |
| Ananya Sharma | 2024-01-15 |
Quick quiz
1. What is the default sort direction?
ASC is used when you do not write a direction.
2. In ORDER BY dept_id, salary DESC, which column is sorted descending?
Each column needs its own DESC.
3. Where does MySQL put NULL in an ascending sort?
MySQL treats NULL as lower than any value.
4. Can ORDER BY use an alias defined in SELECT?
ORDER BY runs after SELECT, so aliases exist.
ORDER BY FAQ
How do I sort in descending order in SQL?
Add DESC after the column: ORDER BY salary DESC. Use ASC (or nothing) for ascending.
How do I sort by multiple columns in SQL?
List them separated by commas: ORDER BY dept_id, salary DESC. Rows are sorted by the first column, and later columns break ties.
Is the row order guaranteed without ORDER BY?
No. Without ORDER BY the database may return rows in any order, and it can change when data, indexes or the query plan change.
How do I put NULL values last in MySQL?
Sort by column IS NULL first: ORDER BY commission IS NULL, commission. MySQL has no NULLS LAST clause.