我需要在我的sql 2005實例的每個數據庫中創建一個觸發器。我正在設置一些審計ddl觸發器。在2005實例的每個數據庫中創建一個DDL觸發器
我創建一個包含所有數據庫名稱的遊標,並嘗試執行USE語句。這似乎沒有改變數據庫 - CREATE TRIGGER語句只是在adventureworks中反覆激發。另一個選項是在觸發器對象前加上databasename.dbo.triggername。這也不起作用 - 在創建觸發器方面存在某種限制。當然,我可以手動執行此操作,但我更願意通過腳本輕鬆進行應用和刪除操作。我有其他選擇,如果我不能在1 sql腳本中做到這一點,但我想保持簡單:)
這是我迄今爲止 - 希望你可以找到一個骨頭錯誤!
--setup stuff...
CREATE DATABASE DBA_AUDIT
GO
USE DBA_AUDIT
GO
CREATE TABLE AuditLog
(ID INT PRIMARY KEY IDENTITY(1,1),
Command NVARCHAR(1000),
PostTime DATETIME,
HostName NVARCHAR(100),
LoginName NVARCHAR(100)
)
GO
CREATE ROLE AUDITROLE
GO
sp_adduser 'guest','guest','AUDITROLE'
GO
GRANT INSERT ON SCHEMA::[dbo]
TO AUDITROLE
--CREATE TRIGGER IN ALL NON SYSTEM DATABASES
DECLARE @dataname varchar(255),
@dataname_header varchar(255),
@command VARCHAR(MAX),
@usecommand VARCHAR(100)
SET @command = '';
--get the list of database names
DECLARE datanames_cursor CURSOR FOR SELECT name FROM sys.databases
WHERE name not in ('master', 'pubs', 'tempdb', 'model','msdb')
OPEN datanames_cursor
FETCH NEXT FROM datanames_cursor INTO @dataname
WHILE (@@fetch_status = 0)
BEGIN
PRINT '----------BEGIN---------'
PRINT 'DATANAME variable: ' + @dataname;
EXEC ('USE ' + @dataname);
PRINT 'CURRENT db: ' + db_name();
SELECT @command = 'CREATE TRIGGER DBA_Audit ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE @data XML
DECLARE @cmd NVARCHAR(1000)
DECLARE @posttime NVARCHAR(24)
DECLARE @spid NVARCHAR(6)
DECLARE @loginname NVARCHAR(100)
DECLARE @hostname NVARCHAR(100)
SET @data = EVENTDATA()
SET @cmd = @data.value(''(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]'', ''NVARCHAR(1000)'')
SET @cmd = LTRIM(RTRIM(REPLACE(@cmd,'''','''')))
SET @posttime = @data.value(''(/EVENT_INSTANCE/PostTime)[1]'', ''DATETIME'')
SET @spid = @data.value(''(/EVENT_INSTANCE/SPID)[1]'', ''nvarchar(6)'')
SET @loginname = @data.value(''(/EVENT_INSTANCE/LoginName)[1]'',
''NVARCHAR(100)'')
SET @hostname = HOST_NAME()
INSERT INTO [DBA_AUDIT].dbo.AuditLog(Command, PostTime,HostName,LoginName)
VALUES(@cmd, @posttime, @hostname, @loginname);'
EXEC (@command);
FETCH NEXT FROM datanames_cursor INTO @dataname;
PRINT '----------END---------'
END
CLOSE datanames_cursor
DEALLOCATE datanames_cursor
OUTPUT:
----------BEGIN---------
DATANAME variable: adventureworks
CURRENT db: master
Msg 2714, Level 16, State 2, Procedure DBA_Audit, Line 18
There is already an object named 'DBA_Audit' in the database.
----------END---------
----------BEGIN---------
DATANAME variable: SQL_DBA
CURRENT db: master
Msg 2714, Level 16, State 2, Procedure DBA_Audit, Line 18
There is already an object named 'DBA_Audit' in the database.
----------END---------
編輯: 我已經嘗試了sp_msforeachdb方法
Msg 111, Level 15, State 1, Line 1
'CREATE TRIGGER' must be the first statement in a query batch.
編輯:
這是我最後的代碼 - 這個確切的腳本尚未經過測試,但它在生產中大約有100個左右的數據庫。乾杯!
一個注意事項 - 您的數據庫需要處於兼容模式(每個數據庫的選項爲90),否則您可能會出現錯誤。聲明的EXECUTE AS部分中的帳戶也需要訪問權限才能插入到管理表中。
USE [SQL_DBA]
GO
/****** Object: Table [dbo].[DDL_Login_Log] Script Date: 03/03/2009 17:28:10 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DDL_Login_Log](
[DDL_Id] [int] IDENTITY(1,1) NOT NULL,
[PostTime] [datetime] NOT NULL,
[DB_User] [nvarchar](100) NULL,
[DBName] [nvarchar](100) NULL,
[Event] [nvarchar](100) NULL,
[TSQL] [nvarchar](2000) NULL,
[Object] [nvarchar](1000) NULL,
CONSTRAINT [PK_DDL_Login_Log] PRIMARY KEY CLUSTERED
(
[DDL_Id] ASC,
[PostTime] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--This creates the trigger on the model database so all new DBs get it
USE [model]
GO
/****** Object: DdlTrigger [ddl_DB_User] Script Date: 03/03/2009 17:26:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [ddl_DB_User]
ON DATABASE
FOR DDL_DATABASE_SECURITY_EVENTS
AS
DECLARE @data XML
declare @user nvarchar(100)
SET @data = EVENTDATA()
select @user = convert(nvarchar(100), SYSTEM_USER)
execute as login='domain\sqlagent'
INSERT sql_dba.dbo.DDL_Login_Log
(PostTime, DB_User, DBName, Event, TSQL,Object)
VALUES
(@data.value('(/EVENT_INSTANCE/PostTime)[1]', 'nvarchar(100)'),
@user,
db_name(),
@data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'),
@data.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'),
@data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(1000)')
)
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--CREATE TRIGGER IN ALL NON SYSTEM DATABASES
DECLARE @dataname varchar(255),
@dataname_header varchar(255),
@command VARCHAR(MAX),
@usecommand VARCHAR(100)
SET @command = '';
DECLARE datanames_cursor CURSOR FOR SELECT name FROM sys.databases
WHERE name not in ('master', 'pubs', 'tempdb', 'model','msdb')
OPEN datanames_cursor
FETCH NEXT FROM datanames_cursor INTO @dataname
WHILE (@@fetch_status = 0)
BEGIN
PRINT '----------BEGIN---------'
PRINT 'DATANAME variable: ' + @dataname;
EXEC ('USE ' + @dataname);
PRINT 'CURRENT db: ' + db_name();
SELECT @command = 'CREATE TRIGGER DBA_Audit ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE @data XML
DECLARE @cmd NVARCHAR(1000)
DECLARE @posttime NVARCHAR(24)
DECLARE @spid NVARCHAR(6)
DECLARE @loginname NVARCHAR(100)
DECLARE @hostname NVARCHAR(100)
SET @data = EVENTDATA()
SET @cmd = @data.value(''(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]'', ''NVARCHAR(1000)'')
SET @cmd = LTRIM(RTRIM(REPLACE(@cmd,'''','''')))
SET @posttime = @data.value(''(/EVENT_INSTANCE/PostTime)[1]'', ''DATETIME'')
SET @spid = @data.value(''(/EVENT_INSTANCE/SPID)[1]'', ''nvarchar(6)'')
SET @loginname = @data.value(''(/EVENT_INSTANCE/LoginName)[1]'',
''NVARCHAR(100)'')
SET @hostname = HOST_NAME()
INSERT INTO [DBA_AUDIT].dbo.AuditLog(Command, PostTime,HostName,LoginName)
VALUES(@cmd, @posttime, @hostname, @loginname);'
EXEC (@command);
FETCH NEXT FROM datanames_cursor INTO @dataname;
PRINT '----------END---------'
END
CLOSE datanames_cursor
DEALLOCATE datanames_cursor
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----Disable all triggers when things go haywire
sp_msforeachdb @command1='use [?]; IF EXISTS (SELECT * FROM sys.triggers WHERE name = N''ddl_DB_User'' AND parent_class=0)disable TRIGGER [ddl_DB_User] ON DATABASE'
GO由SSMS解釋,所以我認爲這不會起作用。但也許我做錯了:'USE'+ @dataname +'GO CREATE Trigger ....'。我添加了分號無濟於事。沒有去,我回到'創建觸發器必須是第一個聲明...' – Sam 2008-12-02 17:46:36