Wie kann ich in Oracle eine Varchar2- oder NVarchar2-Spalte so sortieren, dass sie in meiner benutzerdefinierten Reihenfolge vorliegt? Oder sind vorhandene Optionen verfügbar, bei denen zuerst Buchstaben, dann Zahlen und dann alle Sonderzeichen eingefügt werden?
Unser erster Ansatz war die Verwendung einer Funktion, mit der Zeichen manuell Zahlen zugeordnet werden können.
select id, sorted_column
from some_table
order FN_SPECIAL_SORT_KEY(sorted_column,'asc')
Die spezielle Sortierfunktion ordnet jedes Zeichen einer zweistelligen Zahl zu, und der Rückgabewert wird zum Sortieren verwendet. Dies scheint nur eine sehr teure Verkettung zu sein, und es fühlt sich falsch an.
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;
Es fällt mir schwer, einen alternativen Ansatz zu finden. Ich möchte wissen, welche Probleme mit diesem Ansatz bestehen. Vielleicht haben wir keine Alternativen.
Nachtrag 1:
Beispiel für sortierte Daten hinzufügen. Im Allgemeinen wird bei Großbuchstaben die Groß- und Kleinschreibung nicht berücksichtigt, dann die Zahlen 0 bis 9 und dann die Sonderzeichen in beliebiger Reihenfolge.
Hier ist eine sortierte aufsteigende Beispielliste. Beachten Sie, dass Sonderzeichen austauschbar sind. Sie sollten alle nach Buchstaben und Zahlen stehen. Bei der binären Sortierung stehen einige Sonderzeichen vor Buchstaben (dh ')
Meine gewünschte Bestellung,
AB1 $
aCC #
ac '
BZ
Oracle binäre Reihenfolge
AB1 $
BZ
ac '
acc #
Einige Optionen:
Behalten Sie die sortierte Version Ihrer Daten per Trigger in einer Tabelle bei und verwenden Sie sie.
Verwenden Sie Oracle Locale Builder , um eine benutzerdefinierte Sortierreihenfolge zu erstellen. (Vorsichtsmaßnahme: Ich habe dies noch nie verwendet, daher weiß ich nicht, welche Fallstricke dort vorhanden sein können.) Sie können dann die NLSSORT-Funktion mit dieser benutzerdefinierten Sortierreihenfolge verwenden.
quelle
Ein anderer Ansatz besteht darin, einen funktionsbasierten Index hinzuzufügen
FN_SPECIAL_SORT_KEY(sorted_column,'asc')
. Vermeidet die Notwendigkeit einer zusätzlichen Spalte + eines Auslösers, und Sie müssen Ihre Abfragen nicht ändern.quelle
Basierend auf Ihrer Beschreibung scheint es, dass TRANSLATE die Arbeit für Sie erledigen kann. Wie Jeffrey Kemp vorschlägt, könnte hierfür ein funktionsbasierter Index erstellt werden.
Installieren:
Demonstration:
Ausgabe:
Überprüfen Sie die Reihenfolge aller Zeichen:
quelle
Wenn Sie die Daten indizieren möchten, um eine Sortierung in einer Abfrage mit einem zu vermeiden
order by
, können Sie dies folgendermaßen tun:- bearbeiten
Wie @Leigh kommentiert hat, besteht ein alternativer, übersichtlicherer Ansatz darin, eine einzige Funktion zu haben, die die (modifizierten) regulären Ausdrücke verkettet:
regexp_replace(lower(foo), '[^a-z]', '~')||regexp_replace(foo, '[^a-zA-Z0-9]', '~')||foo
die einschließlich
||foo
am Ende in jedem Fall macht die Bestellung deterministisch (wiederholbaren) , die eine gute Sache selbst sein könnte , wenn die Frage speziell für sie nicht fragen.quelle
regexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9]', '~') || foo
. Das Problem ist, dass dies anders sortiert als Ihre ursprüngliche Lösung. Es ist also die geänderte Version, die diese Korrektur benötigt, nicht Ihr Original. Die Sortierreihenfolge kann durch Ändern des zweiten regulären Ausdrucks festgelegt werden, der eine Reihenfolge von von ergibtregexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9a-zA-Z]', '~') || foo
.