Comment utiliser une variable pour le nom de la base de données dans T-SQL?

123

J'utilise le nom de la base de données à plusieurs endroits dans mon script, et je veux pouvoir le changer rapidement, donc je recherche quelque chose comme ceci:

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

Mais ça ne marche pas. Alors, quelle est la bonne façon d'écrire ce code?

Erick Sasse
la source

Réponses:

135

Placez le script entier dans une chaîne de modèle, avec des espaces réservés {SERVERNAME}. Modifiez ensuite la chaîne en utilisant:

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

puis exécutez-le avec

EXECUTE (@SQL_SCRIPT)

Difficile de croire qu'en l'espace de trois ans, personne n'a remarqué que mon code ne fonctionne pas !

Vous ne pouvez pas EXECplusieurs lots. GOest un séparateur de lots, pas une instruction T-SQL. Il est nécessaire de créer trois chaînes distinctes, puis EXECchacune après la substitution.

Je suppose que l'on pourrait faire quelque chose d '"intelligent" en divisant la chaîne de modèle unique en plusieurs lignes en la divisant GO; Je l'ai fait dans le code ADO.NET.

Et d'où vient le mot "SERVERNAME"?

Voici un code que je viens de tester (et qui fonctionne):

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
la source
2
+1 Très belle approche ... Vous venez de me sauver d'une tonne de travail, merci ... Même si ça devrait être EXECUTE (@SQL_SCRIPT), ou du moins c'est ce qui a fonctionné pour moi.
répété le
2
Il faut cependant faire attention à s'échapper.
usr
4
SYSNAMEserait un type de données plus approprié que celui VARCHAR(255)qui devrait également utiliser QUOTENAMEpour traiter tous les noms de bases de données possibles (et éventuellement pour empêcher l'injection SQL en fonction de la source du nom)
Martin Smith
1
Ne fonctionne pas si je veux CREATE SCHEMAdans une autre base de données, en utilisant USE {DBNAME}. Le schéma crée dans la mauvaise base de données; /
Bomberlt
103

Vous pouvez également utiliser le sqlcmdmode pour cela (activez-le dans le menu "Requête" de Management Studio).

:setvar dbname "TEST" 

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

ÉDITER:

Consultez cet article MSDN pour définir les paramètres via l'outil SQLCMD.

Martin Smith
la source
1
comment cette méthode peut-elle utiliser des variables déjà déclarées? Au lieu de "TEST", pouvez-vous ajouter un @dbName? J'ai essayé et je n'ai pas fonctionné
syclee
1
@syclee Une variable TSQL? Aucune substitution sqlcmd n'est effectuée avant même que le script ne soit envoyé au serveur.
Martin Smith
@MartinSmith Hé, je veux le nom de la base de données comme commande de SORTIE. Alors, comment puis-je l'avoir en utilisant SQLCMD.?
Kunal Kakkad
12

Malheureusement, vous ne pouvez pas déclarer les noms de base de données avec une variable dans ce format.

Pour ce que vous essayez d'accomplir, vous allez devoir encapsuler vos déclarations dans une instruction EXEC (). Vous auriez donc quelque chose comme:

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

Puis appelez

EXECUTE(@Sql) or sp_executesql(@Sql)

pour exécuter la chaîne sql.

Dillie-O
la source
EXECrecherche une procédure stockée. Dans ce cas EXECUTEest nécessaire.
Bob Blogge
2
En fait, je dois m'excuser. Il se trouve EXECet EXECUTEsont les mêmes. J'ai fait cette déclaration après avoir échoué EXECet réussi EXECUTE. Bien évidemment, mon vrai problème n'était pas lié à l'un ou l'autre.
Bob Blogge
2
Ne faites pas ça en production ... Jamais.
Urne magique de poulpe du
@MagicOctopusUrn varie l'ancien post et très de commentaires mais je suis curieux de savoir pourquoi pas? ne devrait-il pas être spécifique à une exigence ??
Harsh
@MagicOctopusUrn Est-ce à cause du potentiel d'injection?
Isaac Reefman
5

Vous ne pouvez pas utiliser une variable dans une instruction create table. La meilleure chose que je puisse suggérer est d'écrire la requête entière sous forme de chaîne et de l'exécuter.

Essayez quelque chose comme ceci:

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

exec (@query);
Andrew Hare
la source