Natural Sort Function PostgreSQL

TODO: collapasable, copyable, download, etc

In postgres how can I do an order by on a string where it will interperate digits as human readable. So 'thread 19' is higher than 'thread 9'?In PostgreSQL, when you want to perform an "order by" operation on a string column such that it interprets digits in a way that humans typically do (e.g., "thread 19" should come after "thread 9"), you can use an approach that involves parsing the string and treating numeric substrings as actual numbers rather than text. This is often referred to as "natural sort" or "human-friendly sort."

PostgreSQL doesn't have built-in support for natural sorting, but you can achieve this with a custom function or by using regular expressions to split the strings into their numeric and non-numeric parts. Below are two approaches you can consider:

Approach 1: Using Regular Expressions

You can use a combination of regular expressions and the string_to_array function to split the string into arrays and then order by these arrays. This method can handle strings with multiple numeric parts:

SELECT *
FROM your_table
ORDER BY
  string_to_array(regexp_replace(column_name, '(\d+)', E'\\1', 'g'), E'\\D+')::int[],
  column_name;

In this SQL snippet:

  • regexp_replace(column_name, '(\d+)', E'\\1', 'g') ensures that digits are isolated.
  • string_to_array(..., E'\\D+') splits the string into arrays using non-digit characters as delimiters.
  • The ::int[] cast attempts to convert each element of the array to integers, which helps in correctly ordering numeric parts.

Approach 2: Creating a Custom Function

You can create a more robust function to handle natural sorting. Here’s an example of how you might define such a function:

CREATE OR REPLACE FUNCTION natural_sort_key(text)
RETURNS text[] AS $$
SELECT array_agg(
  CASE
    WHEN substring(part, '^\d+$') IS NOT NULL THEN lpad(substring(part, '^\d+$'), 10, '0')
    ELSE part
  END
)
FROM regexp_split_to_table($1, E'([^\\d]+|\\d+)') AS part;
$$ LANGUAGE sql IMMUTABLE;

Then, you can use this function in your order by clause:

SELECT *
FROM your_table
ORDER BY natural_sort_key(column_name);

This function:

  • Splits each string into parts of digits and non-digits.
  • Pads numeric parts with zeros on the left to ensure that numbers are compared based on their numeric values rather than as strings.

Both methods should allow you to perform a natural sort in PostgreSQL. Choose the approach that best suits your specific needs, especially considering performance implications if you're dealing with large datasets.

Natural Sort Function PostgreSQL created at Tue Jan 20 1970 20:03:34 GMT+0000 (Coordinated Universal Time)

Related Chats

Natural Sort Function PostgreSQL 0.999

Sort Array with JS 0.346

Digits Calculation and Explanation 0.263

Math Riddle Solution 0.251

Sort Array by messageId 0.235

Cool Ports: Memorable Numbers 0.228

Tests Funktion sortByMessageId 0.223

Prisma Setup and Usage 0.222

Parse Date with Format 0.203

Rust: Replace String Substitution 0.200