Comment puis-je trier dans Oracle une colonne Varchar2 ou NVarchar2 pour qu'elle soit dans mon propre ordre personnalisé défini. Ou existe-t-il des options existantes qui placeront les lettres en premier, puis les chiffres, puis tous les caractères spéciaux.
Notre première approche consistait à utiliser une fonction qui mappe manuellement les caractères aux nombres.
select id, sorted_column
from some_table
order FN_SPECIAL_SORT_KEY(sorted_column,'asc')
La fonction de tri spéciale mappe chaque caractère à un nombre à 2 chiffres et la valeur de retour est utilisée pour le tri. Cela semble être une concaténation vraiment très chère, et cela semble 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;
J'ai du mal à trouver une approche alternative. Je veux savoir quels problèmes existent avec cette approche. Peut-être que nous n'avons pas d'alternatives.
Addendum 1:
Ajout d'un exemple de données triées. En général, tous les caractères alpha ne respectent pas la casse, puis les chiffres 0 à 9, puis les caractères spéciaux dans n'importe quel ordre.
Voici un exemple de liste ascendante triée. Gardez à l'esprit que les caractères spéciaux sont interchangeables, ils devraient tous être après des lettres et des chiffres. En tri binaire, certains caractères spéciaux sont avant les lettres (par exemple ')
Ma commande souhaitée,
AB1 $
aCC #
ac '
BZ
Ordre binaire Oracle
AB1 $
BZ
ac '
acc #
Quelques options:
Conservez la version triée de vos données dans une table via un déclencheur et utilisez-la.
Utilisez Oracle Locale Builder pour créer un ordre de tri personnalisé. (Mise en garde: je n'ai jamais utilisé cela, donc je ne sais pas ce qui peut exister là-bas.) Vous pouvez alors utiliser la fonction NLSSORT avec cet ordre de tri personnalisé.
la source
Une autre approche consiste à ajouter un index basé sur une fonction sur
FN_SPECIAL_SORT_KEY(sorted_column,'asc')
. Évite la nécessité d'une colonne + déclencheur supplémentaire, et vous n'aurez pas besoin de modifier vos requêtes.la source
D'après votre description, TRANSLATE peut faire le travail pour vous. Comme le suggère Jeffrey Kemp, un index basé sur les fonctions pourrait être créé pour cela.
Installer:
Manifestation:
Production:
Vérifiez l'ordre de tous les personnages:
la source
Si vous souhaitez indexer les données pour éviter un tri dans une requête avec un
order by
, vous pouvez le faire comme ceci:-- Éditer
Comme l'a expliqué @Leigh, une approche alternative, plus nette, consiste à avoir une seule fonction concaténant les expressions rationnelles (modifiées):
regexp_replace(lower(foo), '[^a-z]', '~')||regexp_replace(foo, '[^a-zA-Z0-9]', '~')||foo
l'inclusion
||foo
de la fin dans les deux cas rend l'ordonnancement déterministe (répétable), ce qui pourrait être une bonne chose même si la question ne le demande pas spécifiquement.la source
regexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9]', '~') || foo
. Le problème est que cela trie différemment de votre solution d'origine. C'est donc la version modifiée qui a besoin de cette correction, pas l'original. L'ordre de tri peut être fixé en modifiant la deuxième expression rationnelle, qui donne un ordre par deregexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9a-zA-Z]', '~') || foo
.