Skip to main content

PostgreSQL ORDER BY

When querying a database, the order of results can be just as important as the data itself. PostgreSQL's ORDER BY clause gives you precise control over how your query results are sorted, making your data more organized and useful for applications and reports.

Introduction

The ORDER BY clause in PostgreSQL allows you to sort the results of a SELECT query based on one or more columns. Without specifying an order, PostgreSQL returns data in no particular order - typically based on how it's physically stored or how it was processed during the query.

Sorting your query results can help you:

  • Present data in a more readable format
  • Find the highest or lowest values quickly
  • Prepare data for reports or data analysis
  • Create paginated results for applications

Basic Syntax

The basic syntax for the ORDER BY clause is:

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

Where:

  • ASC sorts in ascending order (default if not specified)
  • DESC sorts in descending order

Simple ORDER BY Examples

Let's start with a simple example. Assume we have a students table:

sql
CREATE TABLE students (
id SERIAL PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
age INT,
grade_point_average DECIMAL(3,2)
);

INSERT INTO students (first_name, last_name, age, grade_point_average) VALUES
('John', 'Smith', 20, 3.45),
('Emma', 'Johnson', 21, 3.92),
('Michael', 'Davis', 19, 3.75),
('Sophia', 'Brown', 22, 3.60),
('William', 'Miller', 20, 3.20);

Sorting in Ascending Order (Default)

sql
SELECT * FROM students ORDER BY last_name;

Result:

 id | first_name | last_name | age | grade_point_average 
----+------------+-----------+-----+---------------------
4 | Sophia | Brown | 22 | 3.60
3 | Michael | Davis | 19 | 3.75
2 | Emma | Johnson | 21 | 3.92
5 | William | Miller | 20 | 3.20
1 | John | Smith | 20 | 3.45

Sorting in Descending Order

sql
SELECT * FROM students ORDER BY age DESC;

Result:

 id | first_name | last_name | age | grade_point_average 
----+------------+-----------+-----+---------------------
4 | Sophia | Brown | 22 | 3.60
2 | Emma | Johnson | 21 | 3.92
1 | John | Smith | 20 | 3.45
5 | William | Miller | 20 | 3.20
3 | Michael | Davis | 19 | 3.75

Sorting by Multiple Columns

You can sort by multiple columns to create a more specific order. This is particularly useful when the first column might have duplicate values.

sql
SELECT * FROM students ORDER BY age DESC, grade_point_average DESC;

Result:

 id | first_name | last_name | age | grade_point_average 
----+------------+-----------+-----+---------------------
4 | Sophia | Brown | 22 | 3.60
2 | Emma | Johnson | 21 | 3.92
1 | John | Smith | 20 | 3.45
5 | William | Miller | 20 | 3.20
3 | Michael | Davis | 19 | 3.75

In this example, records are first sorted by age in descending order. When multiple students have the same age (like John and William who are both 20), they are further sorted by their grade point average in descending order.

Sorting by Column Position

PostgreSQL also allows you to sort by column position in the result set:

sql
SELECT first_name, last_name, age FROM students ORDER BY 3 DESC;

Result:

 first_name | last_name | age 
------------+-----------+-----
Sophia | Brown | 22
Emma | Johnson | 21
John | Smith | 20
William | Miller | 20
Michael | Davis | 19

Here, ORDER BY 3 means "sort by the third column in the SELECT list," which is age. While this approach works, using column names is generally preferred for code readability and maintainability.

Sorting with NULLS FIRST/LAST

When dealing with NULL values, you can specify whether they should appear before or after non-NULL values using NULLS FIRST or NULLS LAST:

sql
-- Let's add a student with NULL grade
INSERT INTO students (first_name, last_name, age, grade_point_average) VALUES
('Alex', 'Wilson', 21, NULL);

-- Sorting with NULL handling
SELECT * FROM students ORDER BY grade_point_average DESC NULLS LAST;

Result:

 id | first_name | last_name | age | grade_point_average 
----+------------+-----------+-----+---------------------
2 | Emma | Johnson | 21 | 3.92
3 | Michael | Davis | 19 | 3.75
4 | Sophia | Brown | 22 | 3.60
1 | John | Smith | 20 | 3.45
5 | William | Miller | 20 | 3.20
6 | Alex | Wilson | 21 | NULL

By default, NULL values appear last in ascending order and first in descending order. Using NULLS FIRST or NULLS LAST allows you to override this behavior.

Sorting with Expressions

You can also sort by computed values or expressions:

sql
SELECT first_name, last_name, age, 
grade_point_average * 25 AS percentage
FROM students
ORDER BY percentage DESC;

Result:

 first_name | last_name | age | percentage 
------------+-----------+-----+------------
Emma | Johnson | 21 | 98.00
Michael | Davis | 19 | 93.75
Sophia | Brown | 22 | 90.00
John | Smith | 20 | 86.25
William | Miller | 20 | 80.00
Alex | Wilson | 21 | NULL

Sorting Text Case-Insensitively

To sort text in a case-insensitive manner, you can use the LOWER() or UPPER() functions:

sql
SELECT * FROM students ORDER BY LOWER(last_name);

This ensures 'Apple' and 'apple' would be treated as the same value for sorting purposes.

Real-World Applications

Let's explore some real-world applications for the ORDER BY clause:

Pagination for Web Applications

When implementing pagination for a web application, ORDER BY is essential for maintaining a consistent order across different pages:

sql
SELECT * FROM products
ORDER BY price DESC
LIMIT 10 OFFSET 20; -- Fetch page 3 (10 items per page)

Finding Top Values

To find the top-performing students:

sql
SELECT * FROM students
ORDER BY grade_point_average DESC
LIMIT 3;

Creating Reports with Grouped Data

When creating reports with data aggregated by groups:

sql
SELECT 
department,
COUNT(*) as employee_count,
AVG(salary) as avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;

Building Leaderboards

For applications that need leaderboards:

sql
SELECT username, score
FROM game_scores
WHERE game_id = 1
ORDER BY score DESC
LIMIT 10;

Performance Considerations

While ORDER BY is powerful, it can be costly for large datasets as it requires sorting all matching rows. Here are some performance tips:

  1. Create indexes on columns you frequently sort by:
sql
CREATE INDEX idx_students_gpa ON students(grade_point_average);
  1. Limit sorted results when possible:
sql
SELECT * FROM students
ORDER BY grade_point_average DESC
LIMIT 100;
  1. Avoid sorting by expressions if possible, as they can't use indexes directly.

Common Errors and Troubleshooting

Column Not in SELECT list

In PostgreSQL, you can only sort by columns that are in the SELECT list or from tables in the FROM clause:

sql
-- This will work
SELECT first_name, last_name FROM students ORDER BY age;

-- This will NOT work with GROUP BY
SELECT department, COUNT(*)
FROM employees
GROUP BY department
ORDER BY salary; -- Error: "salary" must appear in GROUP BY

Order Direction Confusion

Remember that ASC (ascending) is the default order. Sometimes results might seem "wrong" because you assumed descending order:

sql
-- This might not give what you expect if you wanted newest first
SELECT * FROM orders ORDER BY order_date;

-- Be explicit for clarity
SELECT * FROM orders ORDER BY order_date DESC;

Summary

The PostgreSQL ORDER BY clause is an essential tool for controlling the presentation of your query results. By understanding its capabilities, you can:

  • Sort data in ascending or descending order
  • Sort by multiple columns for more refined ordering
  • Handle NULL values with NULLS FIRST/LAST
  • Sort by expressions and calculations
  • Implement pagination, reports, and other real-world applications

As your PostgreSQL skills grow, combining ORDER BY with other clauses like WHERE, GROUP BY, and HAVING will allow you to create powerful and precise queries that meet your exact data needs.

Exercises

  1. Create a table for tracking expenses with categories and amounts, then write a query to show expenses sorted by category and then by amount in descending order.

  2. Write a query that finds the three oldest students with the highest grade point averages.

  3. Create a query that sorts products by price ranges (0-9.99, 10-49.99, 50-99.99, 100+) and then alphabetically by name within each range.

Additional Resources



If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)