Come utilizzare una variabile per il nome del database in T-SQL?


123

Uso il nome del database in diversi punti del mio script e voglio essere in grado di cambiarlo rapidamente, quindi sto cercando qualcosa del genere:

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

Ma non funziona. Allora qual è il modo corretto per scrivere questo codice?

Risposte:


135

Inserisci l'intero script in una stringa modello, con segnaposto {SERVERNAME}. Quindi modifica la stringa usando:

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

e poi eseguirlo con

EXECUTE (@SQL_SCRIPT)

È difficile credere che, nel corso di tre anni, nessuno si sia accorto che il mio codice non funziona !

Non puoi EXECpiù batch. GOè un separatore batch, non un'istruzione T-SQL. È necessario costruire tre stringhe separate e poi EXECognuna dopo la sostituzione.

Suppongo che si possa fare qualcosa di "intelligente" spezzando la singola stringa del template in più righe suddividendole GO; L'ho fatto nel codice ADO.NET.

E da dove ho preso la parola "SERVERNAME"?

Ecco del codice che ho appena testato (e che funziona):

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)

2
+1 Approccio molto carino ... Mi hai appena salvato da un sacco di lavoro, grazie ... Anche se dovrebbe essere EXECUTE (@SQL_SCRIPT), o almeno è quello che ha funzionato per me.
RIPRODOTTO il

2
Devi stare attento con la fuga, però.
usr

4
SYSNAMEsarebbe un tipo di dati più appropriato di quello che VARCHAR(255)dovrebbe anche utilizzare QUOTENAMEper gestire tutti i possibili nomi di database (e possibilmente per prevenire l'iniezione di SQL a seconda della fonte del nome)
Martin Smith

1
Non funziona se voglio CREATE SCHEMAin un altro database, utilizzando USE {DBNAME}. Lo schema viene creato nel database sbagliato; /
Bomberlt

103

Puoi anche usare la sqlcmdmodalità per questo (abilitala nel menu "Query" in Management Studio).

:setvar dbname "TEST" 

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

MODIFICARE:

Consulta questo articolo di MSDN per impostare i parametri tramite lo strumento SQLCMD.


1
come può questo metodo utilizzare variabili già dichiarate? Invece di "TEST" puoi aggiungere un @dbName? Ho provato e non ha funzionato
syclee

1
@syclee Una variabile TSQL? No, le sostituzioni di sqlcmd vengono eseguite prima che lo script venga inviato al server.
Martin Smith

@ MartinSmith Ehi, voglio il nome db come comando OUTPUT. Quindi come posso averlo usando SQLCMD.?
Kunal Kakkad

12

Sfortunatamente non puoi dichiarare nomi di database con una variabile in quel formato.

Per quello che stai cercando di ottenere, dovrai racchiudere le tue dichiarazioni all'interno di un'istruzione EXEC (). Quindi avresti qualcosa come:

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

Allora chiama

EXECUTE(@Sql) or sp_executesql(@Sql)

per eseguire la stringa sql.


EXECcerca una procedura memorizzata. In questo caso EXECUTEè necessario.
Bob Blogge

2
In realtà ho bisogno di scusarmi. Si scopre EXECe EXECUTEsono la stessa cosa. Ho fatto la dichiarazione dopo aver fallito EXECe aver avuto successo EXECUTE. Anche se ovviamente il mio vero problema non era correlato a nessuno dei due.
Bob Blogge

2
Non farlo in produzione ... Mai.
Magic Octopus Urn

@MagicOctopusUrn vari vecchi post e commenti molto ma sono curioso di sapere perché no? non dovrebbe essere specifico del requisito?
Duro

@MagicOctopusUrn È a causa del potenziale di iniezione?
Isaac Reefman

5

Non è possibile utilizzare una variabile in un'istruzione create table. La cosa migliore che posso suggerire è scrivere l'intera query come una stringa ed eseguirla.

Prova qualcosa di simile:

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

exec (@query);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.