Considere o seguinte código:
DECLARE @db sysname;
DECLARE @filename varchar(260);
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT d.name
FROM sys.databases d;
OPEN cur;
FETCH NEXT FROM cur INTO @db
WHILE @@FETCH_STATUS = 0
BEGIN
SET @filename = 'C:\temp\create_database_' + @db + '.txt';
:setvar c @filename
:out $(c)
PRINT $(c);
FETCH NEXT FROM cur INTO @db
END
CLOSE cur;
DEALLOCATE cur;
Estou esperando obter vários arquivos criados em C:\temp
, um para cada banco de dados, mas nada é criado e nenhum erro é relatado pelo SQL Server.
Eu tentei executar isso no SSMS usando o modo SQLCMD e também tentei executá-lo no sqlcmd.exe
Usar
SQLCMD
dessa maneira era novo para mim e me fez pesquisar na Internet por exemplos.Depois de estudar as informações no SQL Server Management Studio: Hacking SQLCMD Mode e ponderar sobre as limitações das
SQLCMD
variáveis, adotei uma abordagem um pouco diferente para o seu problema. Minha solução pode não responder totalmente à sua pergunta sobre por que:OUT
não está funcionando conforme o esperado, mas vou oferecê-la de qualquer maneira.Meu script completo está no final da minha resposta, mas aqui estão alguns fragmentos com explicações.
Comecei redirecionando a saída para o diretório temporário do meu usuário local
Agora, invocamos o cursor para ler a lista de bancos de dados. Estou usando o
PRINT
comando para gerarecho
comandos do sistema operacional para criar os arquivos de criação de banco de dados individuais. A saída de toda a execução do cursor é gravada no arquivo DBScript.txt na pasta temporária do meu usuário.Após a execução do acima, o arquivo DBScript.txt agora contém esses comandos (o duplo golpe no início de cada comando indicará
SQLCMD
para executá-los como comandos do sistema operacional):Agora, de volta ao script original, revertemos a
SQLCMD
saída para stdout e executamos os comandos em DBScript.txtQuando olho para o meu diretório C:\Temp, agora tenho os seguintes arquivos individuais:
Aqui está o roteiro completo:
A maneira de fazer isso com o modo sqlcmd é criar um script que cria um script e, em seguida, executar esses scripts, então é uma maneira um pouco diferente de pensar sobre as coisas, um pouco como Inception ou Borges, o sonho dentro do sonho:
Ok, acho que recebo a resposta daqui
gostaria de citar aqui
Isso é tão verdadeiro, em outras palavras, seu
:setvar
e:out
é avaliado primeiro antes que o t-sql seja executado, e isso também explica por que meu t-sql simples mostrado abaixo fornece a mensagem de erroVocê vê, a mensagem de erro tem "não é possível redirecionar a saída para @filename" e 'c:\windows\system32\@filename', é porque, quando :out é avaliado, ele não conhece o valor de @filename, então apenas use a string literal
@filename
para o propósito :out, que será automaticamente padronizado para o caminho padrão de "c:\windows\system32\"