I've got a Postgres ORDER BY
issue with the following table:
em_code name EM001 AAA EM999 BBB EM1000 CCC
To insert a new record to the table,
SELECT * FROM employees ORDER BY em_code DESC
ec_alpha
ec_num
ec_num++
ec_alpha
againWhen em_code
reaches EM1000, the above algorithm fails.
First step will return EM999 instead EM1000 and it will again generate EM1000 as new em_code
, breaking the unique key constraint.
Any idea how to select EM1000?
The ORDER BY clause in PostgreSQL is used together with the SELECT statement to sort table data. The table data can either be sorted in ascending or descending order. By default, the data is sorted in ascending order.
In computing, natural sort order (or natural sorting) is the ordering of strings in alphabetical order, except that multi-digit numbers are treated atomically, i.e., as if they were a single character.
PostgreSQL is a case-sensitive database by default, but provides various possibilities for performing case-insensitive operations and working with collations.
Sorting in PostgreSQLA particular output ordering can only be guaranteed if the sort step is explicitly chosen.
One approach you can take is to create a naturalsort
function for this. Here's an example, written by Postgres legend RhodiumToad.
create or replace function naturalsort(text) returns bytea language sql immutable strict as $f$ select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), 'SQL_ASCII'),'\x00') from regexp_matches($1, '0*([0-9]+)|([^0-9]+)', 'g') r; $f$;
Source: http://www.rhodiumtoad.org.uk/junk/naturalsort.sql
To use it simply call the function in your order by:
SELECT * FROM employees ORDER BY naturalsort(em_code) DESC
The reason is that the string sorts alphabetically (instead of numerically like you would want it) and 1
sorts before 9
. You could solve it like this:
SELECT * FROM employees ORDER BY substring(em_code, 3)::int DESC;
It would be more efficient to drop the redundant 'EM' from your em_code
- if you can - and save an integer number to begin with.
To strip any and all non-digits from a string:
SELECT regexp_replace(em_code, E'\\D','','g') FROM employees;
\D
is the regular expression class-shorthand for "non-digits".'g'
as 4th parameter is the "globally" switch to apply the replacement to every occurrence in the string, not just the first.
After replacing every non-digit with the empty string, only digits remain.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With