Bagaimana mengubah database secara dinamis menggunakan TSQL

11

Saya mengalami masalah dengan mencoba mengubah konteks SSMS secara dinamis ke database yang ditentukan dalam SQL dinamis:

EXEC sys.sp_executesql N'USE db1 ' ;

Ini berhasil dijalankan namun konteks database SSMS tidak berubah.

Saya sudah mencoba sedikit modifikasi di atas seperti itu

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

Sekali lagi, ini berhasil dieksekusi, tetapi database tidak berubah.

Mazhar
sumber
4
Anda tidak dapat mengubah konteks dalam sp_executesql untuk sesi yang Anda gunakan dalam SSMS. Konteksnya hanya valid selama sesi SQL dinamis Anda - bukan untuk sesi SSMS.
Lothar Kraner

Jawaban:

7

SSMS TIDAK AKAN, AKU BEREPEAT, TIDAK AKAN BERALIH DENGAN KONTEKS PENGGUNAAN YANG ANDA PERLU DILAKUKAN DALAM DINAMIKA SQL.

Jika tujuan utamanya adalah untuk menjalankan beberapa SQL dinamis lain di dalam database yang dipilih, ini cukup mudah:

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;

Jika Anda harus melewati parameter, tidak ada masalah:

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;

Jika tujuannya adalah untuk menjalankan beberapa SQL statis di dalam database yang dipilih, mungkin Anda harus mempertimbangkan menyimpan SQL statis itu dalam prosedur tersimpan di setiap database, dan memanggilnya secara dinamis seperti ini:

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;

Dan semoga tujuan akhirnya bukan menjalankan semua kode ini di SSMS hanya agar SSMS sekarang dalam konteks @db... Daniel akan sangat suka jika saya menyatakan secara eksplisit bahwa ini tidak mungkin, seperti komentar @ Lothar juga menyatakan.

Aaron Bertrand
sumber
Ini bagus, terima kasih Aaron Bertrand. Dan tidak, tujuan utamanya bukanlah menjalankan semua kode ini di SSMS hanya agar SSMS sekarang dalam konteks @db
Mazhar
2

DynamicSQL tidak benar-benar dieksekusi khusus in-line dengan sisa kode Anda merupakan entitas yang terpisah (meskipun dijalankan seolah-olah in-line

Jika Anda menjalankan kode: SET @sql = N'Use ' + @db + '; select DB_NAME(); select @@spid'di tempat set Anda saat ini Anda akan melihat hasil yang kembali menunjukkan bahwa Anda telah memindahkan database aktif, tetapi Anda masih berjalan di bawah koneksi yang sama.

Jika Anda ingin mengubah pemilihan database in-line, cara terbaik adalah melakukan sesuatu seperti ini:

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

Tidak bagus atau bersih dan membutuhkan dua baris per basis data potensial tapi itu akan menyelesaikan pekerjaan (jangan jalankan dalam SQL dinamis atau Anda masih akan berakhir dengan masalah yang sama dari utas utama yang tidak diubah)

Perhatikan bahwa penggunaan perintah USE dilarang dalam prosedur / fungsi

Ste Bov
sumber