Dies ist ein Thema, über das ich in der Vergangenheit stundenlang recherchiert habe. Es scheint mir etwas zu sein, das von modernen RDBMS- Lösungen hätte angegangen werden sollen , aber ich habe noch nichts gefunden, das wirklich das anspricht, was ich als unglaublich häufig in einer Web- oder Windows-Anwendung mit einem Datenbank-Back-End betrachte.
Ich spreche von dynamischer Sortierung. In meiner Fantasiewelt sollte es so einfach sein wie:
ORDER BY @sortCol1, @sortCol2
Dies ist das kanonische Beispiel, das von neuen SQL- und Stored Procedure- Entwicklern in allen Foren im Internet gegeben wurde. "Warum ist das nicht möglich?" Sie Fragen. Ausnahmslos kommt irgendwann jemand vorbei, um sie über die Kompilierung gespeicherter Prozeduren, Ausführungspläne im Allgemeinen und viele andere Gründe zu belehren, warum es nicht möglich ist, einen Parameter direkt in eine ORDER BY
Klausel einzufügen.
Ich weiß, was einige von Ihnen bereits denken: "Dann lassen Sie den Kunden die Sortierung durchführen." Dies entlastet natürlich die Arbeit aus Ihrer Datenbank. In unserem Fall sind unsere Datenbankserver jedoch in 99% der Fälle nicht einmal ins Schwitzen geraten, und sie sind noch nicht einmal mehrkernig oder eine der anderen unzähligen Verbesserungen der Systemarchitektur, die alle 6 Monate stattfinden. Allein aus diesem Grund wäre es kein Problem, wenn unsere Datenbanken die Sortierung übernehmen. Darüber hinaus sind Datenbanken sehrgut sortieren. Sie sind dafür optimiert und hatten Jahre Zeit, um es richtig zu machen. Die Sprache dafür ist unglaublich flexibel, intuitiv und einfach. Vor allem jeder SQL-Anfänger weiß, wie es geht, und was noch wichtiger ist, er weiß, wie man es bearbeitet. Nehmen Sie Änderungen vor, führen Sie Wartungsarbeiten durch usw. Wenn Ihre Datenbanken weit davon entfernt sind, besteuert zu werden, und Sie nur die Entwicklungszeit vereinfachen (und verkürzen!) möchten, scheint dies eine naheliegende Wahl zu sein.
Dann gibt es das Webproblem. Ich habe mit JavaScript herumgespielt, das das clientseitige Sortieren von HTML-Tabellen ermöglicht, aber sie sind unweigerlich nicht flexibel genug für meine Anforderungen, und da meine Datenbanken nicht übermäßig besteuert sind und das Sortieren wirklich sehr einfach durchführen können, bin ich es auch Es fällt mir schwer, die Zeit zu rechtfertigen, die erforderlich wäre, um meinen eigenen JavaScript-Sortierer neu zu schreiben oder zu rollen. Das Gleiche gilt im Allgemeinen für die serverseitige Sortierung, obwohl sie wahrscheinlich bereits JavaScript vorgezogen wird. Ich bin nicht einer, der den Overhead von DataSets besonders mag, also verklagen Sie mich.
Dies bringt jedoch den Punkt zurück, dass es nicht möglich ist - oder vielmehr nicht einfach. Ich habe mit früheren Systemen einen unglaublich hackigen Weg gefunden, um eine dynamische Sortierung zu erreichen. Es war weder hübsch noch intuitiv, einfach oder flexibel, und ein Anfänger-SQL-Writer würde innerhalb von Sekunden verloren gehen. Dies scheint bereits weniger eine "Lösung" als vielmehr eine "Komplikation" zu sein.
Die folgenden Beispiele sollen weder Best Practices noch einen guten Codierungsstil oder ähnliches aufzeigen, noch zeigen sie meine Fähigkeiten als T-SQL-Programmierer an. Sie sind das, was sie sind, und ich gebe voll und ganz zu, dass sie verwirrend sind, eine schlechte Form haben und einfach nur hacken.
Wir übergeben einen ganzzahligen Wert als Parameter an eine gespeicherte Prozedur (nennen wir den Parameter nur "sortieren") und bestimmen daraus eine Reihe anderer Variablen. Zum Beispiel ... Nehmen wir an, sort ist 1 (oder die Standardeinstellung):
DECLARE @sortCol1 AS varchar(20)
DECLARE @sortCol2 AS varchar(20)
DECLARE @dir1 AS varchar(20)
DECLARE @dir2 AS varchar(20)
DECLARE @col1 AS varchar(20)
DECLARE @col2 AS varchar(20)
SET @col1 = 'storagedatetime';
SET @col2 = 'vehicleid';
IF @sort = 1 -- Default sort.
BEGIN
SET @sortCol1 = @col1;
SET @dir1 = 'asc';
SET @sortCol2 = @col2;
SET @dir2 = 'asc';
END
ELSE IF @sort = 2 -- Reversed order default sort.
BEGIN
SET @sortCol1 = @col1;
SET @dir1 = 'desc';
SET @sortCol2 = @col2;
SET @dir2 = 'desc';
END
Sie können bereits sehen, wie ich, wenn ich mehr @ colX-Variablen deklariert habe, um andere Spalten zu definieren, mit den zu sortierenden Spalten basierend auf dem Wert von "sort" wirklich kreativ werden könnte ... um sie zu verwenden, sieht sie normalerweise wie folgt aus unglaublich unordentliche Klausel:
ORDER BY
CASE @dir1
WHEN 'desc' THEN
CASE @sortCol1
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END DESC,
CASE @dir1
WHEN 'asc' THEN
CASE @sortCol1
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END,
CASE @dir2
WHEN 'desc' THEN
CASE @sortCol2
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END DESC,
CASE @dir2
WHEN 'asc' THEN
CASE @sortCol2
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END
Offensichtlich ist dies ein sehr reduziertes Beispiel. Das eigentliche Zeug, da wir normalerweise vier oder fünf Spalten haben, um das Sortieren zu unterstützen, jede mit einer möglichen sekundären oder sogar einer dritten Spalte, um zusätzlich zu sortieren (zum Beispiel Datum absteigend, dann sekundär sortiert nach aufsteigendem Namen) und jede unterstützende Bi- Richtungssortierung, die die Anzahl der Fälle effektiv verdoppelt. Ja ... es wird sehr schnell haarig.
Die Idee ist, dass man die Sortierfälle "leicht" so ändern könnte, dass die Fahrzeug-ID vor der Speicherzeit sortiert wird ... aber die Pseudoflexibilität, zumindest in diesem einfachen Beispiel, endet wirklich dort. Im Wesentlichen wird in jedem Fall, in dem ein Test fehlschlägt (da unsere Sortiermethode diesmal nicht darauf angewendet wird), ein NULL-Wert ausgegeben. Und so erhalten Sie eine Klausel, die wie folgt funktioniert:
ORDER BY NULL DESC, NULL, [storagedatetime] DESC, blah blah
Du hast die Idee. Dies funktioniert, weil SQL Server Nullwerte in der Reihenfolge nach Klauseln effektiv ignoriert. Dies ist unglaublich schwer zu pflegen, wie wahrscheinlich jeder mit grundlegenden SQL-Kenntnissen sehen kann. Wenn ich einen von euch verloren habe, fühle dich nicht schlecht. Wir haben lange gebraucht, um es zum Laufen zu bringen, und wir sind immer noch verwirrt, wenn wir versuchen, es zu bearbeiten oder neue wie dieses zu erstellen. Zum Glück muss es nicht oft gewechselt werden, sonst würde es schnell "die Mühe nicht wert" werden.
Doch es tat Arbeit.
Meine Frage ist dann: Gibt es einen besseren Weg?
Ich bin mit anderen Lösungen als den gespeicherten Prozeduren einverstanden, da mir klar ist, dass dies möglicherweise nicht der richtige Weg ist. Am liebsten würde ich wissen, ob jemand es innerhalb der gespeicherten Prozedur besser machen kann, aber wenn nicht, wie gehen Sie alle damit um, dass der Benutzer Datentabellen mit ASP.NET dynamisch (auch bidirektional) sortiert?
Und danke, dass Sie eine so lange Frage gelesen (oder zumindest überflogen) haben!
PS: Seien Sie froh, dass ich mein Beispiel einer gespeicherten Prozedur nicht gezeigt habe, die dynamisches Sortieren, dynamisches Filtern / Textsuchen von Spalten, Paginierung über ROWNUMBER () OVER unterstützt, und versuchen Sie ... mit Transaktions-Rollbacking bei Fehlern zu fangen ... "gigantisch groß" beginnt nicht einmal, sie zu beschreiben.
Aktualisieren:
- Ich möchte dynamisches SQL vermeiden . Das Parsen eines Strings und das Ausführen einer EXEC darauf macht einen großen Teil des Zwecks zunichte, eine gespeicherte Prozedur überhaupt zu haben. Manchmal frage ich mich jedoch, ob sich die Nachteile eines solchen Vorgangs nicht lohnen würden, zumindest in diesen speziellen Fällen der dynamischen Sortierung. Trotzdem fühle ich mich immer schmutzig, wenn ich solche dynamischen SQL-Zeichenfolgen mache - als würde ich immer noch in der klassischen ASP-Welt leben.
- Viele der Gründe, warum wir gespeicherte Prozeduren überhaupt wollen, sind aus Sicherheitsgründen . Ich kann nicht auf Sicherheitsbedenken anrufen, sondern nur Lösungen vorschlagen. Mit SQL Server 2005 können wir Berechtigungen (bei Bedarf auf Benutzerbasis) auf Schemaebene für einzelne gespeicherte Prozeduren festlegen und dann alle Abfragen für die Tabellen direkt ablehnen. Die Vor- und Nachteile dieses Ansatzes zu kritisieren, ist vielleicht eine andere Frage, aber auch hier ist es nicht meine Entscheidung. Ich bin nur der Lead-Code-Affe. :) :)