web-dev-qa-db-ja.com

テーブルの変更を監査するトリガー

テーブルへの変更を監査するトリガーを作成しました。

CREATE TRIGGER [dbo].[iudt_AutoAuditChanges] 
   ON  dbo.CPTCategoryMaster
   AFTER INSERT,DELETE,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    Declare @v_AuditID bigint

    IF OBJECT_ID('dbo.AutoAudit','U') IS NULL BEGIN
        CREATE TABLE [dbo].[AutoAudit]
        (   [AuditID] bigint identity,
            [AuditDate] DateTime,
            [AuditUserName] varchar(128),
            [TableName] varchar(128) NULL,
            [OldContent] XML NULL,
            [NewContent] XML NULL
        )

        ALTER TABLE dbo.AutoAudit ADD CONSTRAINT
        PK_AutoAudit PRIMARY KEY CLUSTERED 
        (
            [AuditID]
        ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

        CREATE NONCLUSTERED INDEX [idx_AutoAudit_TableName_AuditDate] ON [dbo].[AutoAudit] 
        (   [TableName] ASC,
            [AuditDate] ASC
        )WITH (STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    END

    Select * Into #AuditDeleted from deleted
    Select * Into #AuditInserted from inserted

    While (Select COUNT(*) from #AuditDeleted) > 0 OR (Select COUNT(*) from #AuditInserted) > 0
    Begin

        INSERT INTO [dbo].[AutoAudit]
            ( [AuditDate], [AuditUserName], [TableName], [OldContent], [NewContent])
        SELECT 
            GETDATE(),
            SUSER_NAME(),
            [TableName]=object_name([parent_obj]),
            [OldContent]=CAST((SELECT TOP 1 * FROM #AuditDeleted D FOR XML RAW) AS xml),
            [NewContent]=CAST((SELECT TOP 1 * FROM #AuditInserted I FOR XML RAW) AS xml)
        FROM sysobjects 
        WHERE
            [xtype] = 'tr' 
            and [name] = OBJECT_NAME(@@PROCID)

        Set @v_AuditID = SCOPE_IDENTITY()

        Delete from AutoAudit
        Where AuditID = @v_AuditID
            AND Convert(varchar(max),oldContent) = Convert(varchar(max),NewContent)

        Delete top(1) from #AuditDeleted
        Delete top(1) from #AuditInserted

    End
END

これにより、次のようなXMLデータが生成されます。

row CPTCategoryId="1" CPTCategoryName="NEW CHARGE" Remarks="" Status="1" CreatedBy="11" CreatedDate="2014-05-01T12:50:16.947" ModifiedBy="11" ModifiedDate="2014-05-01T14:20:47.793" LockVersion="0" 

列データ(CPTCategoryId, CPTCategoryName, Remarks...など)グリッドビューで表示するには?または、この要件を実装するより良い方法はありますか?

3
rks_dotnet

行に挿入されたすべての列の値をキャッチして、他の監査データを保存するテーブルに保存できます。

ApexSQL Audit のようなサードパーティのツールがあり、そのようなトリガーを作成し、データ(古いものと新しいものの両方のUPDATE)をキャプチャし、レポートを表示します。

次の列を持つテーブルに行が挿入されたとき:

enter image description here

すべての列の値が個別の列として表示されます

enter image description here

あなたはここでより有用な情報を見つけることができます: SQL Serverデータベースの監査トリガー

免責事項:私はApexSQLでサポートエンジニアとして働いています

3
Milena Petrovic

変更されたデータの画像の前後にXMLを挿入するというあなたのアイデアは本当に好きです。私見、それはtriggerに十分な軽量ではありません。 WHILEループ全体を次のように変更しました(別の名前で申し訳ありません)

insert into audit (table_name, old_content, new_content) 
select 
  @table_name,
  case when d.table_id is null then null else (select d.* for xml raw) end,
  case when i.table_id is null then null else (select i.* for xml raw) end
from inserted as i
  full outer join deleted as d on i.table_id = d.table_id

詳細はgithubの yact にあります。

2016年7月11日更新

old_contentおよびnew_content列には、行の変更前イメージと変更後イメージのXML表現が含まれています。

Audit table

3