Wenn überhaupt möglich, tu das nicht.
Das ist die Antwort - es ist ein Anti-Muster. Wenn der Client die Tabelle kennt, aus der er Daten erhalten möchte, dann SELECT FROM ThatTable
. Wenn eine Datenbank so gestaltet ist, dass dies erforderlich ist, scheint sie nicht optimal gestaltet zu sein. Wenn eine Datenzugriffsschicht wissen muss, ob ein Wert in einer Tabelle vorhanden ist, ist es einfach, SQL in diesem Code zu erstellen, und das Verschieben dieses Codes in die Datenbank ist nicht gut.
Für mich scheint dies die Installation eines Geräts in einem Aufzug zu sein, in dem man die Nummer der gewünschten Etage eingeben kann. Nachdem die Go-Taste gedrückt wurde, bewegt sie eine mechanische Hand auf die richtige Taste für den gewünschten Boden und drückt sie. Dies führt zu vielen potenziellen Problemen.
Bitte beachten Sie: Hier besteht keine Spottabsicht. Mein albernes Beispiel für einen Aufzug war * das beste Gerät, das ich mir vorstellen konnte *, um kurz und bündig auf Probleme mit dieser Technik hinzuweisen. Es fügt eine nutzlose Indirektionsebene hinzu und verschiebt die Auswahl von Tabellennamen aus einem Aufruferbereich (unter Verwendung eines robusten und gut verstandenen DSL, SQL) in einen Hybrid, der obskuren / bizarren serverseitigen SQL-Code verwendet.
Eine solche Aufteilung der Verantwortung durch die Verlagerung der Abfragekonstruktionslogik in dynamisches SQL erschwert das Verständnis des Codes. Es verstößt gegen eine standardmäßige und zuverlässige Konvention (wie eine SQL-Abfrage auswählt, was ausgewählt werden soll) im Namen von benutzerdefiniertem Code, der mit potenziellen Fehlern behaftet ist.
Hier finden Sie detaillierte Punkte zu einigen potenziellen Problemen bei diesem Ansatz:
Dynamic SQL bietet die Möglichkeit der SQL-Injection, die im Front-End-Code oder nur im Back-End-Code schwer zu erkennen ist (man muss sie zusammen überprüfen, um dies zu sehen).
Gespeicherte Prozeduren und Funktionen können auf Ressourcen zugreifen, für die der SP- / Funktionsbesitzer Rechte hat, der Aufrufer jedoch nicht. Soweit ich weiß, führt die Datenbank ohne besondere Sorgfalt standardmäßig, wenn Sie Code verwenden, der dynamisches SQL erzeugt und ausführt, das dynamische SQL unter den Rechten des Aufrufers aus. Dies bedeutet, dass Sie entweder überhaupt keine privilegierten Objekte verwenden können oder sie für alle Clients öffnen müssen, um die Oberfläche potenzieller Angriffe auf privilegierte Daten zu vergrößern. Das Festlegen der SP / Funktion zur Erstellungszeit, um immer als ein bestimmter Benutzer (in SQL Server EXECUTE AS
) ausgeführt zu werden, kann dieses Problem lösen, macht die Dinge jedoch komplizierter. Dies erhöht das im vorherigen Punkt erwähnte Risiko einer SQL-Injection, indem das dynamische SQL zu einem sehr verlockenden Angriffsvektor gemacht wird.
Wenn ein Entwickler verstehen muss, was der Anwendungscode tut, um ihn zu ändern oder einen Fehler zu beheben, fällt es ihm sehr schwer, die genaue SQL-Abfrage auszuführen. SQL-Profiler kann verwendet werden, dies erfordert jedoch besondere Berechtigungen und kann negative Auswirkungen auf die Leistung von Produktionssystemen haben. Die ausgeführte Abfrage kann vom SP protokolliert werden, dies erhöht jedoch die Komplexität für fragwürdige Vorteile (das Aufnehmen neuer Tabellen, das Löschen alter Daten usw.) und ist nicht offensichtlich. Tatsächlich sind einige Anwendungen so aufgebaut, dass der Entwickler nicht über Datenbankanmeldeinformationen verfügt, sodass er die übermittelte Abfrage kaum mehr sehen kann.
Wenn ein Fehler auftritt, z. B. wenn Sie versuchen, eine nicht vorhandene Tabelle auszuwählen, wird in der Datenbank eine Meldung mit dem Titel "Ungültiger Objektname" angezeigt. Das wird genauso passieren, egal ob Sie das SQL im Back-End oder in der Datenbank erstellen, aber der Unterschied ist, dass ein armer Entwickler, der versucht, das System zu beheben, eine Ebene tiefer in eine weitere Höhle unterhalb der Höhle spelunk muss Es gibt ein Problem, sich mit der Wunderprozedur zu befassen, die es tut, um herauszufinden, wo das Problem liegt. In den Protokollen wird nicht "Fehler in GetWidget", sondern "Fehler in OneProcedureToRuleThemAllRunner" angezeigt. Diese Abstraktion wird ein System im Allgemeinen verschlechtern .
Ein Beispiel in Pseudo-C # für das Umschalten von Tabellennamen basierend auf einem Parameter:
string sql = $"SELECT * FROM {EscapeSqlIdentifier(tableName)};"
results = connection.Execute(sql);
Dies beseitigt zwar nicht alle denkbaren Probleme, aber die Fehler, die ich mit der anderen Technik skizziert habe, fehlen in diesem Beispiel.