SQL: Stringspalte wie Ziffern sortieren

Aktuell gibt es den Wunsch vom Kunden, eine manuell gepflegte ID-Spalte mit beliebigen (String-)Werten, so zu sortieren, dass der numersiche Teil der ID korrekt, wie bei Ziffern sortiert wird und der alphanumerische Teil "nachgelagert" einsortiert wird.

Beispiel: Die ID-Spalte enthält Werte wie 1, 2, 3, 10, 11, 12, usw.. Aber auch Werte wie 1a, 1b, 1aa, 11aa, 11ab, 11b, 11ba u.ä..
Angezeigt werden soll die Liste so, dass die alphanumerischen Einträge wie "Unterpunkte" behandelt werden, d.h. einsortiert sind.

Mein Lösungsansatz:
select id from t
order by substr (id, 1, length (id) - nvl (length (translate (id, 'a1234567890', 'a')), 0))+1 asc, id asc;


Erläuterung von innen nach außen:
  • translate (id, 'a1234567890', 'a') - Translate entfernt alle Ziffern, zurück bleiben alle alphanumerischen Zeichen


  • length (translate (id, 'a1234567890', 'a')) - Length bestimmt WIEVIELE alphanumerische Zeichen enthalten sind.

  • nvl (length (translate (id, 'a1234567890', 'a')), 0) - NVL ergänzt die Länge 0, falls KEINE alphanumerischen Zeichen enthalten sind

  • substr (id, 1, length (id) - nvl (length (translate (id, 'a1234567890', 'a')), 0)) - Substr "scheidet" den numerischen Teil aus.

  • substr (id, 1, length (id) - nvl (length (translate (id, 'a1234567890', 'a')), 0))+1 asc - "+1" wandelt den Ausdruck in eine Ziffer um. Dies ist die erste Sortierungsebene.

  • substr (id, 1, length (id) - nvl (length (translate (id, 'a1234567890', 'a')), 0))+1 asc, id asc - Die ursprüngliche Spalte bildet die zweite Sortierebene.



Zum Testen hier ein kleines Script:
drop table t;
create table t(id varchar2(10char));

insert into t values ('1');
insert into t values ('2');
insert into t values ('9');
insert into t values ('10');
insert into t values ('11');
insert into t values ('12');
insert into t values ('103');
commit;

select id from t order by id;
--> sortiert alphabetisch, also falsch -> 103 vor 2

insert into t values ('1a');
insert into t values ('1b');
insert into t values ('1aa');
insert into t values ('1ab');
insert into t values ('103ba');
insert into t values ('103ba');

commit;

select id from t order by id;
--> sortiert alphabetisch, also falsch -> 103 vor 2

select id from t
order by substr (id, 1, length (id) - nvl (length (translate (id, 'a1234567890', 'a')), 0))+1 asc, id asc;
--> sortiert wie gewünscht


Einschränkung:
Einträge wie "11ab2c" sind damit NICHT korrekt sortierbar - mein Kunde kann damit leben.

Interessant wäre eine einfachere Lösung. Wenn jemand einen einfacheren Weg kennt, würde ich mich über eine entsprechende Info freuen.

Kommentare

Beliebte Posts aus diesem Blog

PGA unter Oracle 11g

trunc(sysdate) - nette Spiele mit dem Datum

Datapump - Verzeichnis erstellen