Auswerten in T-SQL

8

Ich habe eine gespeicherte Prozedur, die es einem IN-Parameter erlaubt anzugeben, welche Datenbank verwendet werden soll. Ich verwende dann eine vordefinierte Tabelle in dieser Datenbank für eine Abfrage. Das Problem, das ich habe, verkettet den Tabellennamen zu diesem Datenbanknamen innerhalb meiner Abfragen. Wenn T-SQL eine Evaluierungsfunktion hätte, könnte ich etwas wie

tun %Vor%

Momentan bleibe ich beim Erstellen eines Strings und verwende dann exec() , um diesen String als Abfrage auszuführen. Das ist chaotisch und ich möchte lieber keine Saite erstellen. Gibt es eine Möglichkeit, wie ich eine Variable oder eine Zeichenfolge auswerten kann, damit ich etwas wie das Folgende tun kann?

%Vor%

Ich möchte, dass es bewertet wird, damit es so aussieht:

%Vor%     
Joe Phillips 27.03.2009, 03:27
quelle

11 Antworten

16

Lesen Sie dazu ... Der Fluch und Segen des dynamischen SQL , helfen Sie mir sehr zu verstehen, wie Sie diesen Typ lösen können von Problemen.

    
Alan FL 01.04.2009, 20:59
quelle
9

Es gibt keinen "besseren" Weg, dies zu tun. Sie sparen Zeit, wenn Sie es akzeptieren und sich etwas anderes anschauen.

BEARBEITEN: Aha! Zu dem Kommentar des OP: "Wir müssen jeden Monat Daten in eine neue Datenbank laden, sonst wird sie zu groß." Überraschend im Rückblick, dass niemand auf den schwachen Geruch dieses Problems aufmerksam gemacht hat.

SQL Server bietet native Mechanismen für den Umgang mit Tabellen, die "zu groß" sind (insbesondere Partitionierung), so dass Sie die Tabelle als einzelne Entität ansprechen können, während Sie die Tabelle in separate Dateien im Hintergrund aufteilen Beseitigen Sie Ihr aktuelles Problem insgesamt.

Um es anders auszudrücken: Dies ist ein Problem für Ihren DB-Administrator und nicht für den DB-Consumer. Wenn Sie das auch sind, schlage ich vor, dass Sie sich diese Partitionierung ansehen.

    
harpo 27.03.2009 03:40
quelle
5

probiere die eingebaute Funktion sp_executesql. Sie können Ihre SQL-Zeichenfolge im Prinzip in Ihrem proc erstellen und dann

aufrufen %Vor%     
Scott Ferguson 27.03.2009 03:29
quelle
2

Sie können keinen dynamischen Tabellennamen in SQL Server angeben.

Es gibt ein paar Optionen:

  1. Verwenden Sie dynamisches SQL
  2. Spiel mit Synonymen herum (was weniger dynamisches SQL bedeutet, aber immer noch einige)

Du hast gesagt, dass du 1 nicht magst, also lass uns für zwei gehen.

Die erste Möglichkeit besteht darin, die Unordentlichkeit auf eine Zeile zu beschränken:

%Vor%

Ich bin mir nicht sicher, ob mir das gefällt, aber vielleicht ist es die beste Option. Auf diese Weise sind alle SELECTs identisch.

Sie können dies nach Herzenslust umgestalten, aber es gibt eine Reihe von Nachteilen, einschließlich des Synonyms, das in einer Transaktion erstellt wird, so dass Sie nicht zwei haben können     der Abfragen, die gleichzeitig ausgeführt werden     Zeit (weil beide versuchen werden     kreieren Sie temptablesyn). Abhängig     auf die Locking-Strategie wird man     blockiere den anderen.

Synonyme sind permanent, deshalb müssen Sie dies in einer Transaktion tun.

    
Matthew Farwell 01.04.2009 11:16
quelle
1

Es gibt ein paar Optionen, aber sie sind unordentlicher als die, die Sie bereits machen. Ich schlage dir entweder vor:
(1) Bleiben Sie beim derzeitigen Ansatz (2) Gehen Sie voran und binden Sie das SQL in den Code ein, da Sie es ohnehin tun.
(3) Seien Sie besonders vorsichtig, um Ihre Eingabe zu validieren, um SQL Injection zu vermeiden.

Außerdem ist Unordnung nicht das einzige Problem mit dynamischem SQL. Erinnere dich an folgendes:
(1) Dynamic SQL verhindert, dass der Server einen wiederverwendbaren Ausführungsplan erstellen kann.
(2) Der ExecuteSQL-Befehl unterbricht die Besitzkette. Das bedeutet, dass der Code im Kontext des Benutzers ausgeführt wird, der die gespeicherte Prozedur NICHT als Eigentümer der Prozedur aufruft. Dies könnte dazu führen, dass Sie die Sicherheit für die Tabelle öffnen müssen, für die die Anweisung ausgeführt wird, und andere Sicherheitsprobleme verursachen.

    
JohnFx 01.04.2009 21:17
quelle
1

Nur ein Gedanke, aber wenn Sie eine vordefinierte Liste dieser Datenbanken hätten, könnten Sie eine einzelne Ansicht in der Datenbank erstellen, zu der Sie eine Verbindung herstellen, etwa:

%Vor%

Dann könnten Sie Ihren Datenbanknamen an Ihre gespeicherte Prozedur übergeben und ihn einfach als Parameter in einer WHERE-Klausel verwenden. Wenn die Tabellen groß sind, sollten Sie eine indizierte Sicht verwenden, die für die neue Spalte database_name (oder wie immer Sie sie nennen) und den Primärschlüssel der Tabellen indiziert wird (ich gehe von der Frage aus, dass die Schemata der Tabellen gleich sind)? ).

Offensichtlich, wenn sich Ihre Datenbankliste häufig ändert, wird dies problematischer - aber wenn Sie diese Datenbanken trotzdem erstellen müssen, dann sollte die gleichzeitige Pflege dieser Ansicht keinen allzu großen Aufwand bedeuten!

    
David M 04.04.2009 07:20
quelle
1

Ich denke, Mark Brittingham hat die richtige Idee (hier: h ttp: //stackoverflow.com/questions/688425/evaluate-in -t-sql / 718223 # 718223 ), die einen use database -Befehl ausgibt und den SP schreibt, um den Tabellennamen NICHT vollständig zu qualifizieren. Wie er bemerkt, wird dies auf Tabellen in der aktuellen Datenbank des Logins wirken.

Lassen Sie mich ein paar mögliche Ausführungen hinzufügen:

Aus einem Kommentar des OP entnehme ich, dass die Datenbank einmal im Monat geändert wird, wenn sie "zu groß" wird. ("Wir müssen Daten jeden Monat in eine neue Datenbank laden, sonst wird sie zu groß. - d03boy")

  1. Benutzeranmeldungen haben eine Standarddatenbank, die mit sp_defaultdb (veraltet) oder ALTER LOGIN festgelegt wurde. Wenn Sie jeden Monat zur neuen Datenbank wechseln und die älteren Kopien nicht ausführen müssen, ändern Sie einfach die monatliche Standard-Datenbank db und qualifizieren Sie den Tabellennamen nicht vollständig.

  2. Die zu verwendende Datenbank kann im Client-Login festgelegt werden: sqlcmd -U login_id -P password -d db_name , dann führe die SP von dort aus.

  3. Sie können eine Verbindung zur Datenbank herstellen, indem Sie den Client Ihrer Wahl verwenden (Befehlszeile, ODBC, JDBC) und dann einen use database -Befehl ausgeben, die exec die sp.

    Datenbankleiste verwenden; exec sp_foo;

Sobald die Datenbank mit einer der oben genannten Optionen eingerichtet wurde, haben Sie drei Möglichkeiten, die gespeicherte Prozedur auszuführen:

  1. Sie könnten einfach die SP mit der Datenbank in die neue Datenbank kopieren. Solange der Tabellenname NICHT vollständig qualifiziert ist, werden Sie mit der Tabelle der neuen Datenbank arbeiten.

    exec sp_foo;

  2. Sie können die einzelne kanonische Kopie des SP in einer eigenen Datenbank installieren, sie mit procs aufrufen, wobei der Tabellenname nicht vollständig qualifiziert ist, und dann ihren vollständig qualifizierten Namen aufrufen:

    exec procs.dbo.sp_foo;

  3. Sie könnten in jeder einzelnen Datenbank einen Stub sp_foo installieren, der den vollqualifizierten Namen der realen SP ausführt, und dann exec sp_foo , ohne ihn zu qualifizieren. Der Stub wird aufgerufen und ruft die echte Prozedur in procs auf. (Leider kann use database dbname nicht innerhalb einer SP ausgeführt werden.)

    %Vor%

Dies ist jedoch der Fall, wenn die Datenbank geändert wird, sollte die reale SP mit der Option WITH RECOMPILE erstellt werden, andernfalls wird ein Ausführungsplan für die falsche Tabelle zwischengespeichert. Der Stub braucht das natürlich nicht.

    
tpdi 05.04.2009 13:26
quelle
1

Sie können eine SQL CLR-UDF mit Tabellenwert erstellen, um auf die Tabellen zuzugreifen. Sie müssen es an das Schema binden, da TV-UDFs kein dynamisches Schema unterstützen. (Mein Beispiel enthält eine ID und eine Titelspalte - für Ihre Bedürfnisse anpassen)

Sobald Sie dies getan haben, können Sie die folgende Abfrage durchführen:

%Vor%

Sie können auch einen mehrteiligen Namen in diese Zeichenfolge einfügen.

%Vor%

um die ID, Title Spalten aus dieser Tabelle zurückzugeben.

Sie müssen wahrscheinlich SQL CLR aktivieren und die Option TRUSTWORTHY aktivieren:

%Vor%

Erstellen Sie ein C # SQL-Projekt, fügen Sie eine neue UDF-Datei hinzu und fügen Sie sie dort ein. Setze Projekt Property, Datenbank, Permission Level auf external. Erstellen, bereitstellen. Kann ohne VisualStudio gemacht werden. Lass es mich wissen, wenn du das brauchst.

%Vor%     
Hafthor 06.04.2009 18:48
quelle
0
%Vor%

kopiert in eine globale temporäre Tabelle, die Sie dann wie eine normale Tabelle verwenden können

    
Hafthor 05.04.2009 02:12
quelle
0

Wenn Sie über eine relativ überschaubare Anzahl von Datenbanken verfügen, empfiehlt es sich, eine vordefinierte bedingte Anweisung wie folgt zu verwenden:

%Vor%

...

Sie können diesen Proc als Teil Ihrer Datenbankerstellungsskripts generieren, wenn Sie die Liste der Datenbanken ändern, die für die Abfrage verfügbar sind.

Dies vermeidet Sicherheitsbedenken mit dynamischen SQL. Sie können die Leistung auch verbessern, indem Sie die Anweisungen 'select' durch gespeicherte Prozeduren ersetzen, die auf jede Datenbank abzielen (1 zwischengespeicherter Ausführungsplan pro Abfrage).

    
John 05.04.2009 05:30
quelle
0
%Vor%     
Hafthor 08.04.2009 21:42
quelle