作为一些管理任务的一部分,我们有许多需要创建触发器的表。当对象被修改时,触发器将在审核数据库中设置标志和日期。为简单起见,我有一个包含所有需要创建触发器的对象的表。
我正在尝试生成一些动态SQL来为每个对象执行此操作,但是我遇到了以下错误:
如果我使用
我已经删除了
我错过了什么?为什么使用
我正在尝试生成一些动态SQL来为每个对象执行此操作,但是我遇到了以下错误:
'CREATE TRIGGER'必须是查询批处理中的第一条语句。
这是生成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_'+@objname+'_AuditObjectUpdates]'')) '
SET @sql = @sql + N'BEGIN DROP TRIGGER '+QUOTENAME(@schemaname)+'.[Tiud_'+@objname+'_AuditObjectUpdates]; END; '+@CRLF
SET @sql = @sql + N'CREATE TRIGGER '+QUOTENAME(@schemaname)+'.[Tiud_'+@objname+'_AuditObjectUpdates] '+@CRLF
SET @sql = @sql + N' ON '+QUOTENAME(@schemaname)+'.['+@objname+'] '+@CRLF
SET @sql = @sql + N' AFTER INSERT,DELETE,UPDATE'+@CRLF
SET @sql = @sql + N'AS '+@CRLF
SET @sql = @sql + N'IF EXISTS(SELECT * FROM Audit.dbo.ObjectUpdates WHERE DatabaseName = '''+@dbname+''' AND ObjectName = '''+@objname+''' AND RequiresUpdate=0'+@CRLF
SET @sql = @sql + N'BEGIN'+@CRLF
SET @sql = @sql + N' SET NOCOUNT ON;'+@CRLF
SET @sql = @sql + N' UPDATE Audit.dbo.ObjectUpdates'+@CRLF
SET @sql = @sql + N' SET RequiresUpdate = 1'+@CRLF
SET @sql = @sql + N' WHERE DatabaseName = '''+@dbname+''' '+@CRLF
SET @sql = @sql + N' AND ObjectName = '''+@objname+''' '+@CRLF
SET @sql = @sql + N'END' +@CRLF
SET @sql = @sql + N'ELSE' +@CRLF
SET @sql = @sql + N'BEGIN' +@CRLF
SET @sql = @sql + N' SET NOCOUNT ON;' +@CRLF
SET @sql = @sql + @CRLF
SET @sql = @sql + N' -- Update ''SourceLastUpdated'' date.'+@CRLF
SET @sql = @sql + N' UPDATE Audit.dbo.ObjectUpdates'+@CRLF
SET @sql = @sql + N' SET SourceLastUpdated = GETDATE() '+@CRLF
SET @sql = @sql + N' WHERE DatabaseName = '''+@dbname+''' '+@CRLF
SET @sql = @sql + N' AND ObjectName = '''+@objname+''' '+@CRLF
SET @sql = @sql + N'END; '+@CRLF
--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()
内的上下文有关吗?非常感谢任何帮助。
CREATE TRIGGER
语句会抛出以下错误,即使使用了完全限定的表名: “无法在[...]上创建触发器,因为目标不在当前数据库中。” 有没有什么办法解决这个问题?如何在另一个数据库的上下文中执行它? 谢谢。 - MarkusBeeQUOTENAME
函数,其中字符串参数限制为 128 个字符。大于 128 个字符的输入返回NULL
,因此我用引号代替了该函数。 现在我可以看到'EXEC'+@dbname+'..sp_executesql'
可以非常强大,并允许在另一个上下文/数据库中执行动态 SQL。 再次感谢您的帮助。 - MarkusBeeQUOTENAME
的功能。(也就是说,我认为仅仅将@sql
放在引号中是不够的,但因为触发器定义中有字符串表达式,所以你还需要在那里将每个引号都加倍。) - Andriy MREPLACE()
完美地完成了工作。它运行得非常顺利!你刚刚让我的周末变得愉快 :) - MarkusBee