Is it possible to order result rows by a varchar
column cast to integer
in Postgres 8.3?
It's absolutely possible.
ORDER BY varchar_col::int
Be sure to have valid integer literals in your varchar
column for each entry or you get an exception invalid input syntax for integer
. Leading and trailing white space is ok - that's trimmed automatically.
If that's the case, though, then why not convert the column to integer
to begin with? Smaller, faster, cleaner, simpler.
How to avoid exceptions?
Postgres 16 or newer
If the input might not be valid integer literals, use the dedicated function pg_input_is_valid()
to test without raising an exception:
ORDER BY CASE WHEN pg_input_is_valid(varchar_col, 'integer') THEN varchar_col::int END
SQL CASE
defaults to null
in the absence of ELSE
- which sorts last in default ascending order. See:
The new built-in function is faster and more reliable than below manual solution. Also different in that it does not try to fix broken input.
Postgres 15 or older
To remove non-digit characters before the cast and thereby avoid possible exceptions:
ORDER BY NULLIF(regexp_replace(varchar_col, '\D', '', 'g'), '')::int
The
regexp_replace()
expression effectively removes all non-digits, so only digits remain or an empty string. (See below.)\D
is shorthand for the character class[^[:digit:]]
, meaning all non-digits ([^0-9]
).
In old Postgres versions with the outdated settingstandard_conforming_strings = off
, you have to use Posix escape string syntaxE'\\D'
to escape the backslash\
. This was default in Postgres 8.3, so you'll need that for your outdated version.The 4th parameter
g
is for "globally", instructing to replace all occurrences, not just the first.You may want to allow a leading dash (
-
) for negative numbers.If the the string has no digits at all, the result is an empty string which is not valid for a cast to
integer
. Convert empty strings toNULL
withNULLIF
. (You might consider0
instead.)
The result is guaranteed to be valid. This procedure is for a cast to integer
as requested in the body of the question, not for numeric
as the title mentions.
How to make it fast?
One way is an index on an expression.
CREATE INDEX tbl_varchar_col2int_idx ON tbl
(cast(NULLIF(regexp_replace(varchar_col, '\D', '', 'g'), '') AS integer));
Then use the same expression in the ORDER BY
clause:
ORDER BY
cast(NULLIF(regexp_replace(varchar_col, '\D', '', 'g'), '') AS integer)
Test with EXPLAIN ANALYZE
whether the functional index actually gets used.
Also in case you want to order by a text column that has something convertible to float, then this does it:
select *
from your_table
order by cast(your_text_column as double precision) desc;
© 2022 - 2024 — McMap. All rights reserved.