A maneira ideal seria normalizar seus dados e divida os dois componentes da coluna em duas colunas individuais. Um do tipo
integer
, um text
. Com a tabela atual, você pode fazer algo como demonstrado aqui:
WITH x(t) AS (
VALUES
('10_asdaasda')
,('100_inkskabsjd')
,('11_kancaascjas')
,('45_aksndsialcn')
,('22_dsdaskjca')
,('100_skdnascbka')
)
SELECT t
FROM x
ORDER BY (substring(t, '^[0-9]+'))::int -- cast to integer
,substring(t, '[^0-9_].*$') -- works as text
A mesma
substring()
expressões podem ser usadas para dividir a coluna. As expressões regulares são um pouco tolerantes a falhas:
-
A primeira regex escolhe a string numérica mais longa da esquerda,NULL
se nenhum dígito for encontrado, então a conversão parainteger
não pode dar errado.
-
A segunda regex escolhe o resto da string do primeiro caractere que não é um dígito ou '_'.
Se o sublinhado não for ambíguo como separador,
split_part()
é mais rápido:ORDER BY (split_part(t, '_', 1)::int
,split_part(t, '_', 2)
Resposta para o seu exemplo
SELECT name
FROM nametable
ORDER BY (split_part(name, '_', 1)::int
,split_part(name, '_', 2)