sql >> Base de Datos >  >> RDS >> Sqlserver

error de sql dinámico:'CREATE TRIGGER' debe ser la primera declaración en un lote de consulta

Si usa SSMS (u otra herramienta similar) para ejecutar el código producido por this script, obtendrá exactamente el mismo error. Podría funcionar bien cuando insertaste delimitadores de lotes (GO ), pero ahora que no lo hace, también se enfrentará al mismo problema en SSMS.

Por otro lado, la razón por la que no puedes poner GO en sus scripts dinámicos es porque GO no es una instrucción SQL, es simplemente un delimitador reconocido por SSMS y algunas otras herramientas. Probablemente ya lo sepas.

De todos modos, el punto de GO es para que la herramienta sepa que el código debe dividirse y sus partes se ejecutan por separado . Y eso, por separado , es lo que deberías hacer en tu código también.

Entonces, tienes estas opciones:

  • inserte EXEC sp_execute @sql justo después de la parte que suelta el gatillo, luego restablece el valor de @sql para luego almacenar y ejecutar la parte de definición a su vez;

  • usa dos variables, @sql1 y @sql2 , almacene la parte IF EXISTS/DROP en @sql1 , el CREATE TRIGGER en @sql2 , luego ejecute ambos scripts (nuevamente, por separado).

Pero luego, como ya descubrió, se enfrentará a otro problema:no puede crear un disparador en otra base de datos sin ejecutar la declaración en el contexto de esa base de datos .

Ahora, hay 2 formas de proporcionar el contexto necesario:

1) usa un USE declaración;

2) ejecute las declaraciones como una consulta dinámica usando EXEC targetdatabase..sp_executesql N'…' .

Obviamente, la primera opción no va a funcionar aquí:no podemos agregar USE … antes de CREATE TRIGGER , porque esta última debe ser la única declaración en el lote.

La segunda opción puede ser utilizado, pero requerirá una capa adicional de dinámica (no estoy seguro si es una palabra). Es porque el nombre de la base de datos es un parámetro aquí, por lo que necesitamos ejecutar EXEC targetdatabase..sp_executesql N'…' como una secuencia de comandos dinámica, y dado que se supone que la secuencia de comandos real que se ejecutará en sí misma es una secuencia de comandos dinámica, por lo tanto, se anidará dos veces.

Entonces, antes del (segundo) EXEC sp_executesql @sql; línea agregue lo siguiente:

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

Como puede ver, para integrar los contenidos de @sql como un script dinámico anidado correctamente, deben estar entre comillas simples. Por la misma razón, cada comilla simple en @sql debe duplicarse (por ejemplo, usando REPLACE() función , como en la declaración anterior).