Como usar uma variável para o nome do banco de dados no T-SQL?


123

Eu uso o nome do banco de dados em vários lugares do meu script e quero poder alterá-lo rapidamente, por isso estou procurando algo parecido com isto:

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

Mas isso não funciona. Então, qual é a maneira correta de escrever esse código?

Respostas:


135

Coloque o script inteiro em uma sequência de modelos, com espaços reservados {SERVERNAME}. Em seguida, edite a string usando:

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

e execute-o com

EXECUTE (@SQL_SCRIPT)

É difícil acreditar que, no decorrer de três anos, ninguém percebeu que meu código não funciona !

Você não pode EXECvários lotes. GOé um separador de lotes, não uma instrução T-SQL. É necessário construir três strings separadas e depois para EXECcada uma após a substituição.

Suponho que alguém possa fazer algo "inteligente" quebrando a cadeia de modelo único em várias linhas dividindo GO; Eu fiz isso no código ADO.NET.

E de onde eu recebi a palavra "SERVERNAME"?

Aqui está um código que eu acabei de testar (e 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)

2
+1 Abordagem muito boa ... Você acabou de me salvar de uma tonelada de trabalho, thx ... Embora deva ser EXECUTE (@SQL_SCRIPT), ou pelo menos foi o que funcionou para mim.
usar o seguinte código

2
Precisa ter cuidado com a fuga, no entanto.
usr

4
SYSNAMESeria um tipo de dados mais apropriado que VARCHAR(255)também deve usar QUOTENAMEpara lidar com todos os nomes de banco de dados possíveis (e possivelmente a injeção prevent SQL dependendo da fonte do nome)
Martin Smith

1
Não funciona se eu quiser CREATE SCHEMAem outro banco de dados, usando USE {DBNAME}. O esquema cria no banco de dados errado; /
Bomberlt 26/06

103

Você também pode usar o sqlcmdmodo para isso (ative-o no menu "Consulta" no 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:

Verifique este artigo do MSDN para definir parâmetros por meio da ferramenta SQLCMD.


1
como esse método pode usar variáveis ​​já declaradas? Em vez de "TEST", você pode adicionar um @dbName? Eu tentei e não funcionou
syclee

1
@syclee Uma variável TSQL? Nenhuma substituição do sqlcmd é executada antes que o script seja enviado ao servidor.
Martin Smith

@ MartinSmith Ei, eu quero o nome db como um comando OUTPUT. Então, como posso usá-lo usando o SQLCMD.?
Kunal Kakkad

12

Infelizmente, você não pode declarar nomes de bancos de dados com uma variável nesse formato.

Para o que você está tentando realizar, será necessário agrupar suas instruções em uma instrução EXEC (). Então, você teria algo como:

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

Então ligue

EXECUTE(@Sql) or sp_executesql(@Sql)

para executar a string sql.


EXECprocura um procedimento armazenado. Neste caso EXECUTEé necessário.
21713 Bob Blogge

2
Na verdade, preciso me desculpar. Acontece EXECe EXECUTEsão os mesmos. Eu fiz a declaração depois de falhar EXECe ter sucesso com EXECUTE. Embora, obviamente, meu verdadeiro problema não tenha relação com nenhum dos dois.
21713 Bob Blogge

2
Não faça isso em produção ... Ever.
Magic Octopus Urn

@MagicOctopusUrn varia post antigo e muitos comentários, mas estou curioso para saber por que não? não deveria ser requisito específico?
Harsh

@MagicOctopusUrn Isso é devido ao potencial de injeção?
Isaac Reefman 23/05/19

5

Você não pode usar uma variável em uma instrução create table. A melhor coisa que posso sugerir é escrever a consulta inteira como uma string e executá-la.

Tente algo como isto:

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

exec (@query);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.