¿Cómo puedo ordenar en Oracle una columna Varchar2 o NVarchar2 para que esté en mi propio orden definido personalizado? O hay opciones disponibles que pondrán letras primero, luego números, luego todos los caracteres especiales.
Nuestro primer enfoque fue utilizar una función que hace un mapeo manual de caracteres a números.
select id, sorted_column
from some_table
order FN_SPECIAL_SORT_KEY(sorted_column,'asc')
La función especial de clasificación asigna cada carácter a un número de 2 dígitos, y el valor de retorno se utiliza para la clasificación. Esto parece ser una concatenación realmente costosa, y se siente mal.
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;
Me está costando trabajo encontrar un enfoque alternativo. Quiero saber qué problemas existen con este enfoque. Quizás no tenemos alternativas.
Anexo 1:
Agregar ejemplo de datos ordenados. En general, todos los caracteres alfa distinguen entre mayúsculas y minúsculas, luego los números 0-9, luego los caracteres especiales en cualquier orden.
Aquí hay una lista ordenada ascendente de muestra. Tenga en cuenta que los caracteres especiales son intercambiables, todos deben ir después de letras y números. En orden binario, algunos caracteres especiales están antes de las letras (es decir, ')
Mi pedido deseado,
AB1 $
aCC #
ac '
BZ
Orden binario de Oracle
AB1 $
BZ
ac '
acc #
Algunas opciones:
Persista la versión ordenada de sus datos en una tabla a través del activador y utilícela.
Use Oracle Locale Builder para crear un orden de clasificación personalizado. (Advertencia: nunca he usado esto, así que no sé qué trucos pueden existir allí). Luego, podría usar la función NLSSORT con ese orden de clasificación personalizado.
fuente
Otro enfoque es agregar un índice basado en funciones en
FN_SPECIAL_SORT_KEY(sorted_column,'asc')
. Evita la necesidad de una columna adicional + disparador, y no necesitará modificar sus consultas.fuente
Según su descripción, parece que TRANSLATE puede hacer el trabajo por usted. Como sugiere Jeffrey Kemp, se podría crear un índice basado en funciones para esto.
Preparar:
Demostración:
Salida:
Verifique el orden de todos los caracteres:
fuente
Si desea indexar los datos para evitar una ordenación en una consulta con un
order by
, puede hacerlo así:- editar
Como ha comentado @Leigh, un enfoque alternativo y más ordenado es tener una sola función que concatene las expresiones regulares (modificadas):
regexp_replace(lower(foo), '[^a-z]', '~')||regexp_replace(foo, '[^a-zA-Z0-9]', '~')||foo
incluir el
||foo
final en cualquier caso hace que el ordenamiento sea determinista (repetible), lo que podría ser algo bueno aunque la pregunta no lo solicite específicamente.fuente
regexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9]', '~') || foo
. El problema es que esto se clasifica de manera diferente a su solución original. Por lo tanto, es la versión alterada la que necesita esta corrección, no la original. El orden de clasificación se puede corregir cambiando la segunda expresión regular, que da un orden de porregexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9a-zA-Z]', '~') || foo
.