Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

errore sql dinamico:'CREATE TRIGGER' deve essere la prima istruzione in un batch di query

Se utilizzi SSMS (o altro strumento simile) per eseguire il codice prodotto da this script, otterrai esattamente lo stesso errore. Potrebbe funzionare correttamente quando hai inserito delimitatori batch (GO ), ma ora che non lo fai, dovrai affrontare lo stesso problema anche in SSMS.

D'altra parte, il motivo per cui non puoi mettere GO nei tuoi script dinamici è perché GO non è un'istruzione SQL, è semplicemente un delimitatore riconosciuto da SSMS e alcuni altri strumenti. Probabilmente ne sei già consapevole.

Comunque, il punto di GO è che lo strumento sappia che il codice deve essere suddiviso e le sue parti eseguite separatamente . E quello, separatamente , è ciò che dovresti fare anche nel tuo codice.

Quindi, hai queste opzioni:

  • inserisci EXEC sp_execute @sql subito dopo la parte che rilascia il trigger, quindi reimposta il valore di @sql per poi memorizzare ed eseguire a sua volta la parte di definizione;

  • usa due variabili, @sql1 e @sql2 , archivia la parte IF EXISTS/DROP in @sql1 , quello CREATE TRIGGER in @sql2 , quindi esegui entrambi gli script (di nuovo, separatamente).

Ma poi, come hai già scoperto, dovrai affrontare un altro problema:non puoi creare un trigger in un altro database senza eseguire l'istruzione nel contesto di quel database .

Ora, ci sono 2 modi per fornire il contesto necessario:

1) usa un USE dichiarazione;

2) eseguire le istruzioni come query dinamica utilizzando EXEC targetdatabase..sp_executesql N'…' .

Ovviamente, la prima opzione non funzionerà qui:non possiamo aggiungere USE … prima di CREATE TRIGGER , perché quest'ultima deve essere l'unica istruzione nel batch.

La seconda opzione può essere utilizzato, ma richiederà un ulteriore livello di dinamicità (non so se è una parola). È perché il nome del database è un parametro qui e quindi dobbiamo eseguire EXEC targetdatabase..sp_executesql N'…' come uno script dinamico e poiché lo script effettivo da eseguire dovrebbe essere esso stesso uno script dinamico, verrà quindi nidificato due volte.

Quindi, prima del (secondo) EXEC sp_executesql @sql; riga aggiungere quanto segue:

SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
           + REPLACE(@sql, '''', '''''') + '''';

Come puoi vedere, per integrare i contenuti di @sql come script dinamico annidato correttamente, devono essere racchiusi tra virgolette singole. Per lo stesso motivo, ogni singola virgoletta in @sql deve essere raddoppiato (ad es. utilizzando REPLACE() funzione , come nella dichiarazione di cui sopra).