Dynamisches Ändern der Datenbank mit TSQL

11

Ich habe Probleme beim Versuch, den Kontext von SSMS dynamisch in die in dynamischem SQL angegebene Datenbank zu ändern:

EXEC sys.sp_executesql N'USE db1 ' ;

Es wird erfolgreich ausgeführt, der Datenbankkontext von SSMS ändert sich jedoch nicht.

Ich habe versucht, eine geringfügige Änderung an den oben genannten so

DECLARE @sql NVARCHAR(100) DECLARE @db NVARCHAR(50)
SET @db = N'db1' SET @sql = N'Use ' + @db
EXEC sp_executesql @sql

Wieder wird es erfolgreich ausgeführt, aber die Datenbank ändert sich nicht.

Mazhar
quelle
4
Sie können den Kontext innerhalb einer sp_executesql für die Sitzung, die Sie im SSMS verwenden, nicht ändern. Der Kontext ist nur während Ihrer dynamischen SQL-Sitzung gültig - nicht für die SSMS-Sitzung.
Lothar Kraner

Antworten:

7

SSMS WILL NICHT, ich wiederhole, WILL NOT SWITCH TO Kontext eines USE - Befehl Sie führen in dynamischen SQL.

Wenn das ultimative Ziel darin besteht, ein anderes dynamisches SQL in der ausgewählten Datenbank auszuführen, ist dies einfach genug:

DECLARE @db sysname = N'db1';

DECLARE @exec nvarchar(max) = QUOTENAME(@db) + N'.sys.sp_executesql',
        @sql  nvarchar(max) = N'SELECT DB_NAME();';

EXEC @exec @sql;

Wenn Sie Parameter übergeben müssen, kein Problem:

DECLARE @db sysname = N'db1', @i int = 1;

DECLARE @exec nvarchar(max) = QUOTENAME(@db) + N'.sys.sp_executesql',
        @sql  nvarchar(max) = N'SELECT DB_NAME(), @i;';

EXEC @exec @sql, N'@i int', @i;

Wenn das Ziel darin besteht, statisches SQL in der ausgewählten Datenbank auszuführen , sollten Sie dieses statische SQL möglicherweise in einer gespeicherten Prozedur in jeder Datenbank speichern und dynamisch wie folgt aufrufen:

DECLARE @db sysname = N'db1';

DECLARE @exec nvarchar(max) = QUOTENAME(@db) + N'.sys.sp_executesql',
        @sql  nvarchar(max) = N'EXEC dbo.procedurename;';

EXEC @exec @sql;

Und hoffentlich ist das ultimative Ziel nicht, den gesamten Code in SSMS auszuführen, nur damit SSMS jetzt im Kontext von @db... Daniel würde es wirklich mögen, wenn ich ausdrücklich sage, dass dies nicht möglich ist, wie auch der Kommentar von @ Lothar sagte.

Aaron Bertrand
quelle
Das ist großartig, danke Aaron Bertrand. Und nein, das ultimative Ziel ist nicht, den gesamten Code in SSMS auszuführen, nur damit SSMS jetzt im Kontext von @db
Mazhar
2

DynamicSQL wird nicht speziell inline mit dem Rest Ihres Codes ausgeführt, sondern ist eine separate Entität (obwohl es so ausgeführt wird, als ob es inline wäre

Wenn Sie den Code ausführen: SET @sql = N'Use ' + @db + '; select DB_NAME(); select @@spid'In der Palette Ihres aktuellen Satzes werden Sie feststellen, dass die zurückgegebenen Ergebnisse darauf hinweisen, dass Sie die aktive Datenbank verschoben haben, aber immer noch unter derselben Verbindung ausgeführt werden.

Wenn Sie die Auswahl der Inline-Datenbank ändern möchten, gehen Sie am besten wie folgt vor:

IF @db = 'db1'
    USE db1
ELSE IF @db = 'db2'
    USE db2

Es ist nicht schön oder sauber und erfordert zwei Zeilen pro potenzieller Datenbank, aber es erledigt den Job (führen Sie es nicht in dynamischem SQL aus, sonst wird immer noch das gleiche Problem auftreten, dass der Hauptthread nicht geändert wird).

Beachten Sie jedoch, dass die Verwendung von USE-Befehlen in Prozeduren / Funktionen verboten ist

Ste Bov
quelle