Skip to content

MySQL ORDER BY

Overview

The ORDER BY clause sorts the result set by one or more columns. It can sort in ascending (ASC) or descending (DESC) order. By default, results are sorted in ascending order.

ORDER BY Syntax

sql
SELECT column1, column2
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC];

Basic ORDER BY

Ascending Order

sql
-- Default is ASC
SELECT * FROM users ORDER BY name;
SELECT * FROM users ORDER BY name ASC;

-- Sort by name alphabetically
SELECT * FROM products ORDER BY product_name;

Descending Order

sql
-- Use DESC for descending
SELECT * FROM users ORDER BY created_at DESC;

-- Newest first
SELECT * FROM orders ORDER BY created_at DESC;

Multiple Column Sorting

sql
-- Sort by multiple columns
SELECT * FROM users 
ORDER BY country ASC, name ASC;

-- Different directions
SELECT * FROM products 
ORDER BY category ASC, price DESC;

-- Three columns
SELECT * FROM orders 
ORDER BY 
    status ASC,
    created_at DESC,
    total DESC;

Sorting by Position

sql
-- Sort by column position in SELECT
SELECT id, name, email FROM users ORDER BY 2;  -- Sort by name

-- Multiple positions
SELECT id, name, age FROM users ORDER BY 3 DESC, 2;

ORDER BY with Expressions

String Expressions

sql
-- Sort by string length
SELECT * FROM users ORDER BY LENGTH(name);

-- Sort by part of string
SELECT * FROM emails ORDER BY SUBSTRING(email, LOCATE('@', email));

-- Case-insensitive sort
SELECT * FROM users ORDER BY name COLLATE utf8mb4_unicode_ci;

Numeric Expressions

sql
-- Sort by calculation
SELECT * FROM products 
ORDER BY price * quantity DESC;

-- Sort by absolute value
SELECT * FROM transactions 
ORDER BY ABS(amount) DESC;

Date

sql
-- Sort by date part
SELECT * FROM events ORDER BY YEAR(created_at) DESC;

-- Sort by time only
SELECT * FROM schedules ORDER BY TIME(scheduled_at);

-- Sort by relative date
SELECT * FROM users ORDER BY created_at DESC;

NULL Value Sorting

NULL Position

sql
-- NULLs first (default ASC)
SELECT * FROM users ORDER BY phone ASC;  -- NULLs first

-- NULLs last
SELECT * FROM users ORDER BY phone DESC NULLS LAST;

-- In MySQL (NULLs are lowest by default)
SELECT * FROM users ORDER BY phone;          -- NULLs first
SELECT * FROM users ORDER BY phone DESC;     -- NULLs last

COALESCE for NULL Handling

sql
-- Treat NULL as specific value
SELECT * FROM users 
ORDER BY COALESCE(phone, 'N/A');

-- Multiple NULL columns
SELECT * FROM users 
ORDER BY COALESCE(phone, mobile, email, 'No contact');

ORDER BY with LIMIT

Top N Results

sql
-- Get top 10 most expensive products
SELECT * FROM products ORDER BY price DESC LIMIT 10;

-- Get newest 5 users
SELECT * FROM users ORDER BY created_at DESC LIMIT 5;

-- Get oldest 10 orders
SELECT * FROM orders ORDER BY created_at ASC LIMIT 10;

Pagination

sql
-- Page 1 (records 1-10)
SELECT * FROM products ORDER BY price DESC LIMIT 10 OFFSET 0;
SELECT * FROM products ORDER BY price DESC LIMIT 10;  -- Page 1

-- Page 2 (records 11-20)
SELECT * FROM products ORDER BY price DESC LIMIT 10 OFFSET 10;

-- Page 3 (records 21-30)
SELECT * FROM products ORDER BY price DESC LIMIT 10 OFFSET 20;

Random Order

sql
-- Random selection
SELECT * FROM users ORDER BY RAND() LIMIT 10;

-- Random product
SELECT * FROM products ORDER BY RAND() LIMIT 1;

-- Shuffle results
SELECT * FROM items ORDER BY RAND();

ORDER BY in Different Contexts

With JOIN

sql
-- Sort joined results
SELECT u.name, o.order_number, o.total
FROM users u
INNER JOIN orders o ON u.id = o.user_id
ORDER BY o.created_at DESC;

-- Sort by aggregate
SELECT 
    u.name,
    COUNT(o.id) AS order_count,
    SUM(o.total) AS total_spent
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id
ORDER BY total_spent DESC;

With GROUP BY

sql
-- Sort grouped results
SELECT category, COUNT(*) AS product_count
FROM products
GROUP BY category
ORDER BY product_count DESC;

-- Sort by aggregate
SELECT 
    user_id,
    COUNT(*) AS orders,
    AVG(total) AS avg_order
FROM orders
GROUP BY user_id
ORDER BY avg_order DESC;

With Subqueries

sql
-- Sort subquery results
SELECT * FROM (
    SELECT * FROM products WHERE category = 'Electronics'
    ORDER BY price DESC
) AS electronics
LIMIT 10;

-- UNION with ORDER BY
(SELECT id, name FROM current_users ORDER BY created_at DESC LIMIT 10)
UNION
(SELECT id, name FROM archived_users ORDER BY created_at DESC LIMIT 10)
ORDER BY created_at DESC;

Collation and Sorting

Character Set

sql
-- Different collation
SELECT * FROM users ORDER BY name COLLATE utf8mb4_unicode_ci;
SELECT * FROM users ORDER BY name COLLATE utf8mb4_bin;

Case-Insensitive Sort

sql
-- Default is case-insensitive for utf8mb4
SELECT * FROM users ORDER BY name;  -- john, John, JOHN (case-insensitive)

-- Case-sensitive sort
SELECT * FROM users ORDER BY name COLLATE utf8mb4_bin;

Performance Considerations

Index Usage

sql
-- Index helps for sorted columns
CREATE INDEX idx_users_name ON users(name);
SELECT * FROM users ORDER BY name;  -- Uses index

-- Composite index for multiple columns
CREATE INDEX idx_orders_status_date ON orders(status, created_at);
SELECT * FROM orders ORDER BY status, created_at;  -- Uses index

When Indexes Don't Help

sql
-- Expression on column
SELECT * FROM users ORDER BY LENGTH(name);  -- Cannot use index

-- Function on column
SELECT * FROM users ORDER BY YEAR(created_at);  -- Cannot use index

-- Mixed directions
SELECT * FROM orders ORDER BY status ASC, created_at DESC;  -- May not use index

Practical Examples

E-commerce Sorting

sql
-- Sort by price: low to high
SELECT * FROM products ORDER BY price ASC;

-- Sort by price: high to low
SELECT * FROM products ORDER BY price DESC;

-- Sort by rating
SELECT * FROM products ORDER BY rating DESC, reviews DESC;

-- Sort by newest
SELECT * FROM products ORDER BY created_at DESC;

User Management

sql
-- Recently active users
SELECT * FROM users ORDER BY last_activity DESC;

-- Users by registration date
SELECT * FROM users ORDER BY created_at DESC;

-- Alphabetical by last name
SELECT * FROM users ORDER BY last_name, first_name;

Report Sorting

sql
-- Sales by amount
SELECT 
    DATE(created_at) AS date,
    SUM(total) AS daily_sales
FROM orders
WHERE created_at >= '2024-01-01'
GROUP BY DATE(created_at)
ORDER BY daily_sales DESC;

-- Top customers
SELECT 
    user_id,
    COUNT(*) AS orders,
    SUM(total) AS revenue
FROM orders
GROUP BY user_id
ORDER BY revenue DESC
LIMIT 10;

Summary

ORDER BY clause provides:

  • Sorting: ASC (default), DESC
  • Multiple Columns: Sort by multiple columns
  • Expressions: Sort by computed values
  • NULL Handling: NULLs first
  • LIMIT: Top N results
  • Performance: Use indexes for sorting

Previous: UNION

Next: GROUP BY

Content is for learning and research only.