Here is an example of data:
'1.' 'Numeric types'
'1.1.' 'Integer'
'1.2.' 'Float'
...
'1.10' 'Double'
To naturally sort it we can use string_to_array
with '.'
as separator, then cast text[]
to int[]
and sort by integer array, but since the field itself is of type text
and there might be cases where user decides to use non-numeric symbols, e.g. 1.1.3a
, thus causing cast error.
To address that I decided to use regexp:
select regexp_matches('1.2.3.4.', E'(?:(\\d+)\.?)+')
Expected result is array: {'1', '2', '3', '4'}
but instead i get only the last element of the said array, however, if I use following regexp:
select regexp_matches('1.2.3.4.', E'((?:\\d+)\.?)+')
The result is {'1.2.3.4.'}
.
Using global-flag 'g'
is not an option, because regexp_matches
returns a column.
Is there any way to convert '1.2.3.4a.'::text
to {1, 2, 3 ,4}::int[]
using only one regexp_matches
?
You can use the global
'g'
flag withregexp_matches
, but needs to aggregate values to an array (most simple with thearray()
constructor):Or, you can split your string to array with
string_to_array()
, but you still need to use regexp to remove any non-numeric characters:For a more advanced natural-like sorting, you need to split your text to tokens yourself. See more info at the related SO question.
I could come up with a simplified, reusable function:
With this function, natural sorting will be this easy:
SQLFiddle