Jak dynamicznie zmienić bazę danych za pomocą TSQL

11

Mam problem z próbą dynamicznej zmiany kontekstu SSMS na bazę danych określoną w dynamicznym SQL:

EXEC sys.sp_executesql N'USE db1 ' ;

Wykonuje się pomyślnie, jednak kontekst bazy danych SSMS nie zmienia się.

Próbowałem niewielkiej modyfikacji powyższego

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

Ponownie wykonuje się pomyślnie, ale baza danych się nie zmienia.

Mazhar
źródło
4
Nie można zmienić kontekstu w sp_executesql dla sesji używanej w SSMS. Kontekst jest prawidłowy tylko podczas dynamicznej sesji SQL - nie dotyczy sesji SSMS.
Lothar Kraner

Odpowiedzi:

7

SSMS NIE BĘDZIE, POWTARZAĆ, NIE PRZEŁĄCZA SIĘ DO KONTEKSTU POLECENIA UŻYTKOWNIKA W DYNAMICZNYM SQL.

Jeśli ostatecznym celem jest wykonanie innego dynamicznego SQL w wybranej bazie danych, jest to dość łatwe:

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;

Jeśli potrzebujesz przekazać parametry, nie ma problemu:

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;

Jeśli celem jest wykonanie statycznego SQL w wybranej bazie danych, być może powinieneś rozważyć zapisanie tego statycznego SQL w procedurze przechowywanej w każdej bazie danych i wywołanie go dynamicznie w następujący sposób:

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;

I miejmy nadzieję, że ostatecznym celem nie jest uruchomienie całego tego kodu w SSMS, tak aby SSMS był teraz w kontekście @db... Danielowi bardzo by się spodobało, jeśli wyraźnie stwierdzę, że nie jest to możliwe, jak stwierdził również komentarz Lothara.

Aaron Bertrand
źródło
To wspaniale, dzięki Aaron Bertrand. I nie, ostatecznym celem nie jest uruchomienie całego tego kodu w SSMS tylko dlatego, że SSMS jest teraz w kontekście @db
Mazhar
2

DynamicSQL nie jest właściwie wykonywany bezpośrednio w linii z resztą kodu, jest osobną jednostką (nawet jeśli jest uruchamiany tak, jakby był w linii)

Jeśli uruchomisz kod: SET @sql = N'Use ' + @db + '; select DB_NAME(); select @@spid'zamiast obecnego zestawu zauważysz, że wyniki, które powróciły, wskazują, że przeniosłeś aktywną bazę danych, ale nadal działasz w tym samym połączeniu.

Jeśli chcesz zmienić wybór wbudowanej bazy danych, najlepszym sposobem jest zrobienie czegoś takiego:

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

Nie jest ładny ani czysty i wymaga dwóch wierszy na potencjalną bazę danych, ale wykona zadanie (nie uruchamiaj go w dynamicznym SQL, w przeciwnym razie nadal będzie występować ten sam problem, że główny wątek nie zostanie zmieniony)

Należy jednak pamiętać, że używanie poleceń USE jest zabronione w procedurach / funkcjach

Ste Bov
źródło