Como posso classificar no Oracle uma coluna Varchar2 ou NVarchar2 para estar na minha própria ordem definida personalizada. Ou existem opções disponíveis que colocarão primeiro as letras, os números e todos os caracteres especiais.
Nossa primeira abordagem foi usar uma função que faz um mapeamento manual de caracteres para números.
select id, sorted_column
from some_table
order FN_SPECIAL_SORT_KEY(sorted_column,'asc')
A função de classificação especial mapeia cada caractere para um número de 2 dígitos e o valor de retorno é usado para classificação. Isso parece ser apenas uma concatenação realmente cara e parece errado.
for i in 1..length(sorted_text)
loop
v_result:=v_result || case substr(sorted_text,i,1)
WHEN ' ' THEN 82 WHEN '!' THEN 81 WHEN '"' THEN 80 WHEN '#' THEN 79 WHEN '$'
..............
WHEN 'u' THEN 15 WHEN 'U' THEN 15 WHEN 'v' THEN 14 WHEN 'V' THEN 14 WHEN 'w' THEN 13 WHEN 'W' THEN 13 WHEN 'x'
....
else 90 end;
end loop;
Estou tendo dificuldades para propor uma abordagem alternativa. Quero saber que problemas existem com essa abordagem. Talvez não tenhamos alternativas.
Adenda 1:
Adicionando exemplo de dados classificados. Em geral, todos os caracteres alfa não fazem distinção entre maiúsculas e minúsculas e, em seguida, números de 0 a 9, depois caracteres especiais em qualquer ordem.
Aqui está um exemplo de lista ascendente classificada. Lembre-se de que caracteres especiais são intercambiáveis; todos devem estar depois de letras e números. No tipo binário, alguns caracteres especiais estão antes das letras (ie ')
Meu pedido desejado,
AB1 $
aCC #
ac '
BZ
Ordem binária do Oracle
AB1 $
BZ
ac '
acc #
fonte
Algumas opções:
Persista a versão classificada de seus dados para uma tabela via gatilho e use-a.
Use o Oracle Locale Builder para criar uma ordem de classificação personalizada. (Advertência: nunca usei isso, então não sei quais truques podem existir lá.) Em seguida, você poderia usar a função NLSSORT com essa ordem de classificação personalizada.
fonte
Outra abordagem é adicionar um índice baseado em função
FN_SPECIAL_SORT_KEY(sorted_column,'asc')
. Evita a necessidade de uma coluna extra + gatilho, e você não precisará modificar suas consultas.fonte
Com base na sua descrição, parece que o TRANSLATE pode fazer o trabalho por você. Como Jeffrey Kemp sugere, um índice baseado em função pode ser criado para isso.
Configuração:
Demonstração:
Resultado:
Verifique a ordem de todos os caracteres:
fonte
Se você deseja indexar os dados para evitar uma classificação em uma consulta com um
order by
, faça o seguinte:- editar
Como o @Leigh comentou, uma abordagem alternativa, mais pura, é ter uma única função concatenando os regexs (modificados):
regexp_replace(lower(foo), '[^a-z]', '~')||regexp_replace(foo, '[^a-zA-Z0-9]', '~')||foo
a inclusão de
||foo
no final, em ambos os casos, torna a ordem determinística (repetível), o que pode ser uma coisa boa, mesmo que a pergunta não a peça especificamente.fonte
regexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9]', '~') || foo
. O problema é que isso é diferente da sua solução original. Portanto, é a versão alterada que precisa dessa correção, não o original. A ordem de classificação pode ser corrigida alterando o segundo regex, que fornece uma ordem por deregexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9a-zA-Z]', '~') || foo
.