それで、私はこのことと数時間戦い続けて、少しでも助けを求めて手を差し伸べると思いました。データベースのすべてのテーブルに監査トリガーを作成する必要があります(この監査トリガーは機能し、テスト済みです)。各テーブルを手動で展開してスクリプトを作成するのではなく、簡単に展開する方法を見つけようとしています。
これがトリガーを作成するために作成したprocです
alter PROCEDURE [dbo].[InsertTRIGGER]
(@triggerTable varchar(max))
AS
DECLARE @sql nvarchar(max)
SET @sql = ('
CREATE TRIGGER [dbo].[TR_@triggertable_AUDIT] ON [dbo].[@triggertable] FOR UPDATE, INSERT, DELETE
AS
DECLARE @bit INT ,
@field INT ,
@maxfield INT ,
@char INT ,
@fieldname VARCHAR(128) ,
@TableName VARCHAR(128) ,
@PKCols VARCHAR(1000) ,
@sql VARCHAR(2000),
@UpdateDate VARCHAR(21) ,
@UserName VARCHAR(128) ,
@Type CHAR(1) ,
@PKSelect VARCHAR(1000),
@UserGroup VARCHAR(128),
IF IS_MEMBER (''DbEditAudit'') = 1
BEGIN
--You will need to change @TableName to match the table to be audited.
-- Here we made GUESTS for your example.
SELECT @TableName = ''@triggertable''
-- date and user
SELECT @UserName = SYSTEM_USER ,
@UpdateDate = CONVERT (NVARCHAR(30),GETDATE(),126)
-- Action
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT @Type = ''U''
ELSE
SELECT @Type = ''I''
ELSE
SELECT @Type = ''D''
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT @PKCols = COALESCE(@PKCols + '' and'', '' on'')
+ '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = ''PRIMARY KEY''
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT @PKSelect = COALESCE(@PKSelect+''+'','''')
+ ''''''<'' + COLUMN_NAME
+ ''=''''+convert(varchar(100),
coalesce(i.'' + COLUMN_NAME + '',d.'' + COLUMN_NAME + '')) + ''''>''''''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = @TableName
AND CONSTRAINT_TYPE = ''PRIMARY KEY''
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF @PKCols IS NULL
BEGIN
RAISERROR(''no PK on table %s'', 16, -1, @TableName)
RETURN
END
SELECT @field = 0,
@maxfield = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName
WHILE @field < @maxfield
BEGIN
SELECT @field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION > @field
SELECT @bit = (@field - 1 )% 8 + 1
SELECT @bit = POWER(2,@bit - 1)
SELECT @char = ((@field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0
OR @Type IN (''I'',''D'')
BEGIN
SELECT @fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND ORDINAL_POSITION = @field
SELECT @sql = ''
insert Audit ( Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName)
select '''''' + @Type + '''''',''''''
+ @TableName + '''''','' + @PKSelect
+ '','''''' + @fieldname + ''''''''
+ '',convert(varchar(1000),d.'' + @fieldname + '')''
+ '',convert(varchar(1000),i.'' + @fieldname + '')''
+ '','''''' + @UpdateDate + ''''''''
+ '','''''' + @UserName + ''''''''
+ '' from #ins i full outer join #del d''
+ @PKCols
+ '' where i.'' + ''@fieldname'' + '' <> d.'' + ''@fieldname''
+ '' or (i.'' + ''@fieldname'' + '' is null and d.''
+ ''@fieldname''
+ '' is not null)''
+ '' or (i.'' + @fieldname + '' is not null and d.''
+ ''@fieldname''
+ '' is null)''
EXEC (@sql)
END
END
END
')
EXECUTE sp_executesql @sql, N'@triggertable nvarchar(max)', @triggertable = @triggertable
これが、テーブルの名前をプルして各テーブルのトリガーにデータを入力するために作成したカーソルです。
DECLARE @table varchar(100)
DECLARE trigger_cursor CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE' AND TABLE_NAME NOT LIKE '%_audit'
OPEN trigger_cursor
FETCH NEXT FROM trigger_cursor INTO @table
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC [InsertTRIGGER] @triggertable = '@table'
FETCH NEXT FROM trigger_cursor INTO @table
END
CLOSE trigger_cursor
DEALLOCATE trigger_cursor
私が得ているエラーはこれです
メッセージ156、レベル15、状態1、行3キーワード「TRIGGER」の近くの構文が正しくありません。メッセージ156、レベル15、状態1、23行目キーワード「IF」の近くの構文が正しくありません。メッセージ137、レベル15、状態1、27行目スカラー変数「@TableName」を宣言する必要があります。メッセージ137、レベル15、状態1、行30スカラー変数「@UserName」を宣言する必要があります。メッセージ137、レベル15、状態1、行37
実際にはすべての変数がリストされていますが、すでにたくさん投稿しているので、目を離さないでください。
簡単なことだと思います。2つ目の目が必要です。問題は、トリガーを作成するprocの最初、または@sqlを実行する最後にあると思います。
トリガーの名前の一部として、およびテーブルの名前として、使用できない場所で変数を使用しようとしています。 @triggertable
をパラメーターとして渡す代わりに、SQLステートメントに直接連結して、次のように置き換えることもできます。
@triggertable
と:
' + @triggertable + '
次に、必要な結果が得られるはずです。システムテーブルからテーブル名を取得していることを考えると、ここでSQLインジェクションについて実際に心配する必要はありません。カーソルがテーブル名を返す方法を再確認してください。場合によっては、次のように返されることがあります。
[tablename]
ただの代わりに:
tablename
Kenneth Fisherが指摘したように、実行する代わりに@sql
を印刷して、目的のように見えることを確認してください(sp_executesql
に渡したパラメーターを削除したため)。