Bagaimana cara menggunakan variabel untuk nama database di T-SQL?

123

Saya menggunakan nama database di beberapa tempat di skrip saya, dan saya ingin dapat dengan cepat mengubahnya, jadi saya mencari sesuatu seperti ini:

DECLARE @DBNAME VARCHAR(50)
SET @DBNAME = 'TEST'

CREATE DATABASE @DBNAME
GO
ALTER DATABASE @DBNAME SET COMPATIBILITY_LEVEL = 90
GO
ALTER DATABASE @DBNAME SET RECOVERY SIMPLE 
GO

Tapi itu tidak berhasil. Jadi, apa cara yang benar untuk menulis kode ini?

Erick Sasse
sumber

Jawaban:

135

Letakkan seluruh skrip ke dalam string template, dengan placeholder {SERVERNAME}. Kemudian edit string menggunakan:

SET @SQL_SCRIPT = REPLACE(@TEMPLATE, '{SERVERNAME}', @DBNAME)

dan kemudian jalankan dengan

EXECUTE (@SQL_SCRIPT)

Sulit dipercaya bahwa, selama tiga tahun, tidak ada yang memperhatikan bahwa kode saya tidak berfungsi !

Anda tidak dapat melakukan EXECbanyak kelompok. GOadalah pemisah batch, bukan pernyataan T-SQL. Anda perlu membangun tiga string terpisah, lalu ke EXECmasing - masing string setelah substitusi.

Saya kira seseorang dapat melakukan sesuatu yang "pintar" dengan memecah string template tunggal menjadi beberapa baris dengan membelah GO; Saya telah melakukannya dalam kode ADO.NET.

Dan dari mana saya mendapatkan kata "SERVERNAME"?

Berikut beberapa kode yang baru saja saya uji (dan yang berfungsi):

DECLARE @DBNAME VARCHAR(255)
SET @DBNAME = 'TestDB'

DECLARE @CREATE_TEMPLATE VARCHAR(MAX)
DECLARE @COMPAT_TEMPLATE VARCHAR(MAX)
DECLARE @RECOVERY_TEMPLATE VARCHAR(MAX)

SET @CREATE_TEMPLATE = 'CREATE DATABASE {DBNAME}'
SET @COMPAT_TEMPLATE='ALTER DATABASE {DBNAME} SET COMPATIBILITY_LEVEL = 90'
SET @RECOVERY_TEMPLATE='ALTER DATABASE {DBNAME} SET RECOVERY SIMPLE'

DECLARE @SQL_SCRIPT VARCHAR(MAX)

SET @SQL_SCRIPT = REPLACE(@CREATE_TEMPLATE, '{DBNAME}', @DBNAME)
EXECUTE (@SQL_SCRIPT)

SET @SQL_SCRIPT = REPLACE(@COMPAT_TEMPLATE, '{DBNAME}', @DBNAME)
EXECUTE (@SQL_SCRIPT)

SET @SQL_SCRIPT = REPLACE(@RECOVERY_TEMPLATE, '{DBNAME}', @DBNAME)
EXECUTE (@SQL_SCRIPT)
John Saunders
sumber
2
+1 Pendekatan yang sangat bagus ... Anda baru saja menyelamatkan saya dari banyak pekerjaan, thx ... Meskipun itu harus EXECUTE (@SQL_SCRIPT), atau setidaknya itulah yang berhasil bagi saya.
direSPAWNed
2
Perlu berhati-hati saat melarikan diri.
usr
4
SYSNAMEakan menjadi tipe data yang lebih tepat daripada yang VARCHAR(255)juga harus digunakan QUOTENAMEuntuk menangani semua kemungkinan nama database (dan mungkin untuk mencegah injeksi SQL tergantung pada sumber nama)
Martin Smith
1
Tidak berfungsi jika saya ingin CREATE SCHEMAdi database lain, menggunakan USE {DBNAME}. Skema membuat dalam database yang salah; /
Bomberlt
103

Anda juga dapat menggunakan sqlcmdmode untuk ini (aktifkan ini pada menu "Query" di Management Studio).

:setvar dbname "TEST" 

CREATE DATABASE $(dbname)
GO
ALTER DATABASE $(dbname) SET COMPATIBILITY_LEVEL = 90
GO
ALTER DATABASE $(dbname) SET RECOVERY SIMPLE 
GO

EDIT:

Periksa artikel MSDN ini untuk mengatur parameter melalui alat SQLCMD.

Martin Smith
sumber
1
bagaimana metode ini menggunakan variabel yang sudah dideklarasikan? Selain "TEST", bisakah Anda menambahkan @dbName? Saya mencoba dan tidak berhasil
syclee
1
@ Siklus A variabel TSQL? Tidak ada substitusi sqlcmd yang dilakukan bahkan sebelum skrip dikirim ke server.
Martin Smith
@MartinSmith Hei saya ingin nama db sebagai perintah OUTPUT. Jadi bagaimana saya bisa memilikinya menggunakan SQLCMD.?
Kunal Kakkad
12

Sayangnya Anda tidak dapat mendeklarasikan nama database dengan variabel dalam format itu.

Untuk apa yang Anda coba capai, Anda perlu membungkus pernyataan Anda dalam pernyataan EXEC (). Jadi Anda akan memiliki sesuatu seperti:

DECLARE @Sql varchar(max) ='CREATE DATABASE ' + @DBNAME

Kemudian panggil

EXECUTE(@Sql) or sp_executesql(@Sql)

untuk mengeksekusi string sql.

Dillie-O
sumber
EXECmencari prosedur yang tersimpan. Dalam hal EXECUTEini dibutuhkan.
Bob Blogge
2
Sebenarnya saya perlu minta maaf. Ternyata EXECdan EXECUTEsama saja. Saya membuat pernyataan itu setelah gagal EXECdan berhasil EXECUTE. Meskipun jelas masalah saya sebenarnya tidak terkait dengan keduanya.
Bob Blogge
2
Jangan lakukan ini dalam produksi ... Selamanya.
Magic Octopus Urn
@MagicOctopusUrn bervariasi posting lama dan sangat komentar tapi saya penasaran tahu kenapa tidak? bukankah itu harus menjadi persyaratan khusus ??
Harsh
@MagicOctopusUrn Apakah itu karena potensi injeksi?
Isaac Reefman
5

Anda tidak dapat menggunakan variabel dalam pernyataan buat tabel. Hal terbaik yang dapat saya sarankan adalah menulis seluruh kueri sebagai string dan mengeksekusinya.

Coba sesuatu seperti ini:

declare @query varchar(max);
set @query = 'create database TEST...';

exec (@query);
Andrew Hare
sumber