В рамках некоторых административных задач у нас есть много таблиц, каждая из которых требует создания триггера. Триггер установит флаг и дату в базе данных аудита, когда объект был изменен. Для простоты у меня есть таблица со всеми объектами, для которых созданы триггеры.динамическая ошибка sql: «CREATE TRIGGER» должен быть первым оператором в пакете запросов
Я пытаюсь создать некоторый динамический SQL, чтобы сделать это для каждого объекта, но я получаю эту ошибку:
'CREATE TRIGGER' must be the first statement in a query batch.
Вот код для создания 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
Если я использую PRINT
и вставить код в новом окне запроса, код выполняется без каких-либо проблем.
Я удалил операторы GO
, так как это также давало ошибки.
Что мне не хватает?
Почему я получаю сообщение об ошибке, используя EXEC(@sql);
или даже EXEC sp_executesql @sql;
?
Это как-то связано с контекстом в пределах EXEC()
?
Большое спасибо за любую помощь.
Большое спасибо за это. Теперь я разделил код на две части, как вы предлагаете в своем первом варианте выше, следующим образом: – MarkusBee
[EDIT приурочен к предыдущему комментарию.] Большое спасибо. Я разделил код на две части, как вы предлагаете в своем первом варианте. Первая часть выполняется отлично. Я поясню, что процедура выполняется из базы данных «Аудит», а объекты, требующие триггеры, находятся в других базах данных. Вывод выражения 'CREATE TRIGGER' теперь вызывает следующую ошибку, даже если используется полное имя таблицы: « Невозможно создать триггер на [...], поскольку цель не находится в текущей базе данных ». Есть ли способ обойти это? Как я могу заставить его выполнить в контексте другой базы данных? Спасибо. – MarkusBee
@markb: см. Мое обновление. Я не уверен, все ли так ясно, как хотелось бы, поэтому, пожалуйста, не стесняйтесь спрашивать. –