C'est tout à fait possible.
ORDER BY varchar_column::int
Assurez-vous d'avoir des littéraux entiers valides dans votre varchar
colonne pour chaque entrée ou vous obtenez une exception invalid input syntax for integer: ...
. (Les espaces blancs de début et de fin sont acceptables - ils seront automatiquement coupés.)
Si tel est le cas, alors pourquoi ne pas convertir la colonne en integer
pour commencer? Plus petit, plus rapide, plus propre, plus simple.
Comment éviter les exceptions ?
Pour supprimer les caractères non numériques avant le cast et éviter ainsi d'éventuelles exceptions :
ORDER BY NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '')::int
-
Le
regexp_replace()
expression supprime efficacement tous les non-chiffres, il ne reste donc que des chiffres ou une chaîne vide. (Voir ci-dessous.) -
\D
est un raccourci pour la classe de caractères[^[:digit:]]
, c'est-à-dire tous les non-chiffres ([^0-9]
).
Dans les anciennes versions de Postgres avec le paramètre obsolètestandard_conforming_strings = off
, vous devez utiliser la syntaxe de chaîne d'échappement PosixE'\\D'
pour échapper la barre oblique inverse\
. C'était la valeur par défaut dans Postgres 8.3, vous en aurez donc besoin pour votre version obsolète. -
Le 4ème paramètre
g
est pour "globalement" , demandant de remplacer tous occurrences, pas seulement la première. -
Vous pouvez souhaitez autoriser un tiret initial (
-
) pour les nombres négatifs. -
Si la chaîne n'a aucun chiffre, le résultat est une chaîne vide qui n'est pas valide pour une conversion en
integer
. Convertir les chaînes vides enNULL
avecNULLIF
. (Vous pourriez considérer0
à la place.)
Le résultat est garanti valide. Cette procédure est pour un transtypage en integer
comme demandé dans le corps de la question, pas pour numeric
comme le titre l'indique.
Comment faire vite ?
Une façon est un index sur une expression.
CREATE INDEX tbl_varchar_col2int_idx ON tbl
(cast(NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '') AS integer));
Utilisez ensuite la même expression dans le ORDER BY
clause :
ORDER BY
cast(NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '') AS integer)
Testez avec EXPLAIN ANALYZE
si l'index fonctionnel est réellement utilisé.