Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

erro de SQL dinâmico:'CREATE TRIGGER' deve ser a primeira instrução em um lote de consulta


Se você usar o SSMS (ou outra ferramenta semelhante) para executar o código produzido por este script, você obterá exatamente o mesmo erro. Pode funcionar bem quando você insere delimitadores de lote (GO ), mas agora que não, você também enfrentará o mesmo problema no SSMS.

Por outro lado, a razão pela qual você não pode colocar GO em seus scripts dinâmicos é porque GO não é uma instrução SQL, é apenas um delimitador reconhecido pelo SSMS e algumas outras ferramentas. Provavelmente você já está ciente disso.

De qualquer forma, o ponto de GO é para a ferramenta saber que o código deve ser dividido e suas partes executadas separadamente . E isso, separadamente , é o que você deve fazer em seu código também.

Então, você tem essas opções:

  • insira EXEC sp_execute @sql logo após a parte que descarta o gatilho, redefina o valor de @sql para então armazenar e executar a parte de definição por sua vez;

  • use duas variáveis, @sql1 e @sql2 , armazene a parte IF EXISTS/DROP em @sql1 , o CREATE TRIGGER em @sql2 , execute os dois scripts (novamente, separadamente).

Mas então, como você já descobriu, você enfrentará outro problema:você não pode criar um gatilho em outro banco de dados sem executar a instrução no contexto desse banco de dados .

Agora, existem 2 maneiras de fornecer o contexto necessário:

1) use um USE declaração;

2) execute a(s) instrução(ões) como uma consulta dinâmica usando EXEC targetdatabase..sp_executesql N'…' .

Obviamente, a primeira opção não funcionará aqui:não podemos adicionar USE … antes de CREATE TRIGGER , porque o último deve ser a única instrução no lote.

A segunda opção pode ser usado, mas exigirá uma camada adicional de dinamicidade (não tenho certeza se é uma palavra). É porque o nome do banco de dados é um parâmetro aqui e, portanto, precisamos executar o EXEC targetdatabase..sp_executesql N'…' como um script dinâmico e, como o script real a ser executado deve ser um script dinâmico, ele será aninhado duas vezes.

Então, antes do (segundo) EXEC sp_executesql @sql; linha adicione o seguinte:
SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
           + REPLACE(@sql, '''', '''''') + '''';

Como você pode ver, para integrar o conteúdo de @sql como um script dinâmico aninhado corretamente, eles devem ser colocados entre aspas simples. Pela mesma razão, todas as aspas simples em @sql deve ser duplicado (por exemplo, usando o REPLACE() função , como na afirmação acima).