PostgreSQL: ASC sorting, but NULL values first/last

Updated: January 6, 2024 By: Guest Contributor Post a comment

Introduction

Sorting data is a fundamental aspect of SQL query operations, especially in databases like PostgreSQL. However, the default behavior is to place NULLs at the end for ASC ordering, which might not always be desired. This tutorial explores ways to customize NULL positioning in ASC sorts.

Understanding Nulls in Sorting

In PostgreSQL, when retrieving data with an ORDER BY clause, NULL values are considered to be larger than any non-null value by default. Therefore, when sorting in ascending order, NULLs will appear last, and in descending order, they’ll appear first. While this behavior aligns with the SQL standard, there may be instances where you would like to place the NULLs at the start of the result set even when sorting in ascending order.

Placing NULLs First in ASC Order

To accomplish this, PostgreSQL provides the NULLS FIRST option that can be used in the ORDER BY clause. Here’s a basic example:

SELECT your_column
FROM your_table
ORDER BY your_column ASC NULLS FIRST;

With this clause, the query will return results with NULLs positioned before any non-null values.

Handling Multiple Columns

When sorting by multiple columns, one might want to have NULLs first in one column and last in another. It’s achievable by specifying NULLS FIRST or NULLS LAST for each column:

SELECT column1, column2
FROM your_table
ORDER BY column1 ASC NULLS FIRST, column2 DESC NULLS LAST;

This would place NULLs at the beginning of column1 and at the end of column2.

Advanced NULL Handling Techniques

In more complex queries, you may want to sort based on a computed expression or sort NULLs according to a specific logic. This section will show how to deal with such scenarios with the ORDER BY clause.

Case Statement Sorting

You can use a CASE statement within your ORDER BY clause to handle NULLs in a custom way:

SELECT your_column
FROM your_table
ORDER BY CASE WHEN your_column IS NULL THEN 1 ELSE 0 END, your_column;

This CASE statement essentially creates a virtual column that has a higher value when your_column is NULL.

Using COALESCE

COALESCE can also be a powerful tool for sorting. It returns the first non-null value in a list of arguments:

SELECT your_column
FROM your_table
ORDER BY COALESCE(your_column, '{some_default_value_that_comes_first_in_order}') ASC;

Replacing NULLs with a default value that would naturally order first according to your conditions will ensure that those rows are treated accordingly.

Performance Considerations

Keep in mind that using functions like COALESCE or CASE in the ORDER BY clause can sometimes lead to performance issues, especially with large datasets, because they might prevent the use of indexes.

Working with NULLS on Indexed Columns

If the column you’re ordering by is indexed, consider including an expression index to handle NULLs efficiently:

CREATE INDEX your_column_idx_on_nulls
ON your_table ((CASE WHEN your_column IS NULL THEN 0 ELSE 1 END), your_column);

This index creation can help maintain performance even when custom sorting.

NULL Values and Aggregate Functions

When aggregating, PostgreSQL ignores NULL values by default. However, when aggregates are part of a sort operation, you might want to consider them. Combining COALESCE with aggregate functions can come to the rescue:

SELECT your_column, COUNT(*), COALESCE(SUM(another_column), 0)
FROM your_table
GROUP BY your_column
ORDER BY COALESCE(SUM(another_column), 0) DESC NULLS LAST;

This will ensure that NULLs produced by the SUM operation are considered as zeros.

Practical Example

Let’s consider a practical example where we have a users table with the columns ‘id’ and ‘last_login’. We want to sort the users by their ‘last_login’ dates in ascending order, but keeping the ones who have never logged in (NULL ‘last_login’) at the very top:

SELECT id, last_login
FROM users
ORDER BY last_login ASC NULLS FIRST;

This query makes sure that new users are prioritized in the list, followed by those who have logged in, starting from the most dated login.

Conclusion

By carefully utilizing the NULLS FIRST and NULLS LAST options in conjunction with other SQL tools like the CASE statement and COALESCE function, you can create highly tuned queries that handle NULLs in sorting behavior exactly according to your application’s requirements. While it’s generally good practice to maintain consistent sorting logic, don’t let default behaviors restrict the potential of your queries, especially when dealing with multifaceted data models.