Como parte de algunas tareas administrativas, tenemos muchas tablas en las que cada una necesita un activador. El desencadenador establecerá un indicador y la fecha en la base de datos de auditoría cuando se modificó un objeto. Para simplificar, tengo una tabla con todos los objetos que necesitan triggers creados.error de sql dinámico: 'CREATE TRIGGER' debe ser la primera instrucción en un lote de consulta
Estoy tratando de generar algo de SQL dinámico para hacer esto para cada objeto, pero yo estoy consiguiendo este error:
'CREATE TRIGGER' must be the first statement in a query batch.
Este es el código para generar el SQL.
CREATE PROCEDURE [spCreateTableTriggers]
AS
BEGIN
DECLARE @dbname varchar(50),
@schemaname varchar(50),
@objname varchar(150),
@objtype varchar(150),
@sql nvarchar(max),
@CRLF varchar(2)
SET @CRLF = CHAR(13) + CHAR(10);
DECLARE ObjectCursor CURSOR FOR
SELECT DatabaseName,SchemaName,ObjectName
FROM Audit.dbo.ObjectUpdates;
SET NOCOUNT ON;
OPEN ObjectCursor ;
FETCH NEXT FROM ObjectCursor
INTO @dbname,@schemaname,@objname;
WHILE @@FETCH_STATUS=0
BEGIN
SET @sql = N'USE '+QUOTENAME(@dbname)+'; '
SET @sql = @sql + N'IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'''+QUOTENAME(@schemaname)+'.[Tiud_'[email protected]+'_AuditObjectUpdates]'')) '
SET @sql = @sql + N'BEGIN DROP TRIGGER '+QUOTENAME(@schemaname)+'.[Tiud_'[email protected]+'_AuditObjectUpdates]; END; '[email protected]
SET @sql = @sql + N'CREATE TRIGGER '+QUOTENAME(@schemaname)+'.[Tiud_'[email protected]+'_AuditObjectUpdates] '[email protected]
SET @sql = @sql + N' ON '+QUOTENAME(@schemaname)+'.['[email protected]+'] '[email protected]
SET @sql = @sql + N' AFTER INSERT,DELETE,UPDATE'[email protected]
SET @sql = @sql + N'AS '[email protected]
SET @sql = @sql + N'IF EXISTS(SELECT * FROM Audit.dbo.ObjectUpdates WHERE DatabaseName = '''[email protected]+''' AND ObjectName = '''[email protected]+''' AND RequiresUpdate=0'[email protected]
SET @sql = @sql + N'BEGIN'[email protected]
SET @sql = @sql + N' SET NOCOUNT ON;'[email protected]
SET @sql = @sql + N' UPDATE Audit.dbo.ObjectUpdates'[email protected]
SET @sql = @sql + N' SET RequiresUpdate = 1'[email protected]
SET @sql = @sql + N' WHERE DatabaseName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N' AND ObjectName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N'END' [email protected]
SET @sql = @sql + N'ELSE' [email protected]
SET @sql = @sql + N'BEGIN' [email protected]
SET @sql = @sql + N' SET NOCOUNT ON;' [email protected]
SET @sql = @sql + @CRLF
SET @sql = @sql + N' -- Update ''SourceLastUpdated'' date.'[email protected]
SET @sql = @sql + N' UPDATE Audit.dbo.ObjectUpdates'[email protected]
SET @sql = @sql + N' SET SourceLastUpdated = GETDATE() '[email protected]
SET @sql = @sql + N' WHERE DatabaseName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N' AND ObjectName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N'END; '[email protected]
--PRINT(@sql);
EXEC sp_executesql @sql;
FETCH NEXT FROM ObjectCursor
INTO @dbname,@schemaname,@objname;
END
CLOSE ObjectCursor ;
DEALLOCATE ObjectCursor ;
END
Si uso PRINT
y pegar el código para una nueva ventana de consulta, el código se ejecuta sin ningún problema.
He eliminado las declaraciones GO
ya que esto también estaba dando errores.
¿Qué me estoy perdiendo?
¿Por qué me sale un error al usar EXEC(@sql);
o incluso EXEC sp_executesql @sql;
?
¿Tiene esto algo que ver con el contexto dentro de EXEC()
?
Muchas gracias por cualquier ayuda.
Muchas gracias por esto. Ahora he dividido el código en dos "piezas" como sugiere en su primera opción anterior, de la siguiente manera: – MarkusBee
[EDIT agotó el tiempo de espera en el comentario anterior] Muchas gracias. He dividido el código en dos "piezas" como sugieres en tu primera opción. La primera parte se ejecuta perfectamente. Aclararé que el procedimiento se ejecuta desde la base de datos 'Auditoría' y que los objetos que requieren desencadenantes se encuentran en otras bases de datos. Al exceder la instrucción 'CREATE TRIGGER' ahora se produce el siguiente error, incluso cuando se utiliza el nombre de tabla totalmente calificado: " No se puede crear el desencadenador [...] ya que el destino no está en la base de datos actual. " ¿Hay alguna forma de evitar esto? ¿Cómo puedo hacer que se ejecute dentro del contexto de otra base de datos? Gracias. – MarkusBee
@markb: Por favor, mira mi actualización. No estoy seguro si todo está tan claro como me gustaría, así que no dude en preguntar. –