¿Cómo usar una variable para el nombre de la base de datos en T-SQL?

123

Utilizo el nombre de la base de datos en varios lugares en mi secuencia de comandos, y quiero poder cambiarlo rápidamente, así que estoy buscando algo como esto:

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

Pero no funciona. Entonces, ¿cuál es la forma correcta de escribir este código?

Erick Sasse
fuente

Respuestas:

135

Coloque el script completo en una cadena de plantilla, con marcadores de posición {SERVERNAME}. Luego edite la cadena usando:

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

y luego ejecutarlo con

EXECUTE (@SQL_SCRIPT)

¡Es difícil creer que, en el transcurso de tres años, nadie se dio cuenta de que mi código no funciona !

No puedes EXECvarios lotes. GOes un separador de lotes, no una declaración T-SQL. Es necesario construir tres cadenas separadas y luego EXECcada una después de la sustitución.

Supongo que uno podría hacer algo "inteligente" al dividir la cadena de plantilla única en varias filas dividiéndola GO; Lo hice en el código ADO.NET.

¿Y de dónde saqué la palabra "SERVERNAME"?

Aquí hay un código que acabo de probar (y que funciona):

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
fuente
2
+1 Enfoque muy agradable ... Acabas de salvarme de un montón de trabajo, gracias ... Aunque debería ser EJECUTAR (@SQL_SCRIPT), o al menos eso es lo que funcionó para mí.
REPARADO
2
Sin embargo, debes tener cuidado al escapar.
Usr
44
SYSNAMEsería un tipo de datos más apropiado que el que VARCHAR(255)debería usarse QUOTENAMEpara tratar con todos los nombres de bases de datos posibles (y posiblemente para evitar la inyección de SQL dependiendo de la fuente del nombre)
Martin Smith
1
No funciona si quiero CREATE SCHEMAen otra base de datos, usando USE {DBNAME}. El esquema se crea en una base de datos incorrecta; /
Bomberlt
103

También puede usar el sqlcmdmodo para esto (habilítelo en el menú "Consulta" en Management Studio).

:setvar dbname "TEST" 

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

EDITAR:

Consulte este artículo de MSDN para establecer parámetros a través de la herramienta SQLCMD.

Martin Smith
fuente
1
¿Cómo puede este método utilizar variables ya declaradas? En lugar de "PRUEBA", ¿puede agregar un @dbName? Lo intenté y no
funcioné
1
@syclee ¿Una variable TSQL? No se realizan las sustituciones sqlcmd incluso antes de que el script se envíe al servidor.
Martin Smith
@ MartinSmith Hola, quiero el nombre de db como un comando OUTPUT. Entonces, ¿cómo puedo tenerlo usando SQLCMD?
Kunal Kakkad
12

Lamentablemente, no puede declarar nombres de bases de datos con una variable en ese formato.

Para lo que está tratando de lograr, necesitará ajustar sus declaraciones dentro de una declaración EXEC (). Entonces tendrías algo como:

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

Luego llame

EXECUTE(@Sql) or sp_executesql(@Sql)

para ejecutar la cadena sql.

Dillie-O
fuente
EXECbusca un procedimiento almacenado. En este caso EXECUTEes necesario.
Bob Blogge
2
En realidad necesito disculparme. Resulta EXECy EXECUTEson los mismos. Hice la declaración después de fallar EXECy tener éxito EXECUTE. Aunque obviamente mi verdadero problema no estaba relacionado con ninguno de los dos.
Bob Blogge
2
No hagas esto en producción ... Nunca.
Urna de pulpo mágico
@MagicOctopusUrn varían publicación antigua y muy comentarios, pero tengo curiosidad por saber por qué no? ¿No debería ser un requisito específico?
Duro
@MagicOctopusUrn ¿Eso se debe al potencial de inyección?
Isaac Reefman
5

No puede usar una variable en una instrucción de creación de tabla. Lo mejor que puedo sugerir es escribir toda la consulta como una cadena y ejecutar eso.

Intenta algo como esto:

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

exec (@query);
Andrew Hare
fuente