Wie zu sortieren und gemischte Listen von Alphas und Zahlen angezeigt werden, da die Nutzer erwarten?
-
23-08-2019 - |
Frage
Unsere Anwendung hat eine CustomerNumber
Feld. Wir haben Hunderte von verschiedenen Personen mit dem System (jeder hat seine eigene Login und ihre eigene Liste von CustomerNumber
s). Ein einzelner Benutzer kann höchstens 100.000 Kunden. Viele haben weniger als 100.
nur Einige Leute tatsächliche Zahlen setzen in ihre Kundennummer Felder, während andere eine Mischung aus Dingen verwenden. Das System ermöglicht es, die 20 Zeichen von A-Z sein kann, 0-9, oder ein Strich, und speichert diese in einem VARCHAR2 (20). Alles, was Kleingroß gemacht wird, bevor gespeichert werden.
Nun lassen Sie uns sagen, dass wir einen einfachen Bericht haben, die alle Kunden für einen bestimmten Benutzer auflistet, durch Kundennummer sortiert. z.
SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;
Dies ist eine naive Lösung, wie die Menschen, die je nur Zahlen verwenden wollen nicht eine einfache alphabetische Sortierung sehen (wobei „10“ kommt vor „9“).
Ich mag nicht den Benutzer keine unnötigen Fragen über ihre Daten fragen.
Ich bin mit Oracle, aber ich denke, es wäre interessant, einige Lösungen für andere Datenbanken zu sehen. Bitte geben Sie die Datenbank, um Ihre Antwort arbeitet an.
Was denken Sie, der beste Weg, dies zu realisieren ist?
Lösung
In Oracle 10g:
SELECT cust_name
FROM t_customer c
ORDER BY
REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+'))
Dies wird durch das erste Auftreten von Zahl sortieren, nicht in Bezug auf sie Position ist, i. e.
-
customer1 < customer2 < customer10
-
cust1omer ? customer1
-
cust8omer1 ? cust8omer2
-
, wobei ein ?
bedeutet, dass die Reihenfolge nicht definiert ist.
Das reicht für die meisten Fälle.
Um Sortierreihenfolge auf Fall 2
zwingen Sie ein REGEXP_INSTR(cust_name, '[0-9]', n)
kostenlos in der Liste ORDER BY
mal n
, zwingt, um auf dem ersten Auftreten von n
-ten (2nd
, 3rd
etc.) Zifferngruppe.
Um Sortierreihenfolge auf Fall 3
zu zwingen, können Sie eine TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n))
hinzufügen Liste ORDER BY
mal n
und zwingt Reihenfolge der n
-ten. Zifferngruppe.
In der Praxis ist die Abfrage, die ich geschrieben habe, ist genug.
Sie können eine Funktion basierenden Index auf diesem Ausdrücken erstellen, aber Sie werden es mit einem Hauch zwingen müssen, und eine One-Pass SORT ORDER BY
ohnehin durchgeführt werden, da die CBO
nicht funktionsBasisIndizes genug vertraut zu erlauben eine ORDER BY
auf sie.
Andere Tipps
Wahrscheinlich die beste Wahl ist, um eine separate Spalte vorab zu berechnen und zu verwenden, die für die Bestellung und die Kundennummer für die Anzeige verwenden. Dies würde wahrscheinlich bedeuten 0-padding alle internen Zahlen auf eine feste Länge.
Die andere Möglichkeit ist Ihre Sortier Post-select auf den zurückgegebenen Ergebnissen zu tun.
Jeff Atwood hat zusammen ein Blog-Posting darüber, wie berechnen einige Leute menschliche freundliche Sortierungen.
Sie können eine numerische Spalte [CustomerNumberInt], dass nur verwendet, wenn die Kundennummer rein numerisch ist (NULL ansonsten [1]), dann
ORDER BY CustomerNumberInt, CustomerNumber
[1] je nachdem, wie Sie Ihre SQL-Version behandelt NULL-Werte in ORDER BY Sie ihn auf Null auf Standard möchten (oder unendlich!)
Ich habe eine ähnliche schreckliche Situation und haben eine entsprechend schreckliche Funktion mit ihr umgehen (SQLServer)
entwickeltIn meiner Situation habe ich eine Tabelle von „Einheiten“ (dies ist ein Work-Tracking-System für Studenten, so Einheit in diesem Zusammenhang stellt einen Kurs sie tun). Einheiten haben einen Code, der zum größten Teil rein numerisch ist, aber aus verschiedenen Gründen war es ein varchar gemacht und sie beschlossen, einige von bis zu 5 Zeichen Präfix. So erwarten sie 53123237356 normalerweise zu sortieren, sondern auch T53, T123, T237, T356
Unitcode ist ein nvarchar (30)
Hier ist der Körper der Funktion:
declare @sortkey nvarchar(30)
select @sortkey =
case
when @unitcode like '[^0-9][0-9]%' then left(@unitcode,1) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-1)
when @unitcode like '[^0-9][^0-9][0-9]%' then left(@unitcode,2) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-2)
when @unitcode like '[^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,3) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-3)
when @unitcode like '[^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,4) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-4)
when @unitcode like '[^0-9][^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,5) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-5)
when @unitcode like '%[^0-9]%' then @unitcode
else left('000000000000000000000000000000',30-len(@unitcode)) + @unitcode
end
return @sortkey
Ich wollte mich ins Gesicht schießen nach dem Schreiben, dass, aber es funktioniert und scheint nicht auf den Server zu töten, wenn es ausgeführt wird.
habe ich dies in SQL Server und Arbeiten groß: Hier ist die Lösung der numerischen Werte mit einem Zeichen vor aufzufüllen, so dass alle sind von der gleichen Stringlänge
.Hier ist ein Beispiel mit diesem Ansatz:
select MyCol
from MyTable
order by
case IsNumeric(MyCol)
when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
else MyCol
end
Die 100 sollte mit der tatsächlichen Länge der Spalte ersetzt werden.