sql >> データベース >  >> RDS >> Sqlserver

SQLServerのレコード変更を監査テーブルに記録する

    PopRivettによるSimple-talk.comのこの記事をご覧ください。更新されたすべての列のOLDVALUEとNEWVALUEをログに記録する汎用トリガーの作成について説明します。このコードは非常に一般的であり、監査する任意のテーブルに適用できます。また、任意のCRUD操作(INSERT、UPDATE、DELETE)にも適用できます。唯一の要件は、監査対象のテーブルに主キーが必要であるということです(とにかく、最も適切に設計されたテーブルには主キーが必要です)。

    GUESTSテーブルに関連するコードは次のとおりです。

    1. AUDITテーブルを作成します。
        IF NOT EXISTS
              (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[dbo].[Audit]') 
                       AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
               CREATE TABLE Audit 
                       (Type CHAR(1), 
                       TableName VARCHAR(128), 
                       PK VARCHAR(1000), 
                       FieldName VARCHAR(128), 
                       OldValue VARCHAR(1000), 
                       NewValue VARCHAR(1000), 
                       UpdateDate datetime, 
                       UserName VARCHAR(128))
        GO
    
    1. 次のように、GUESTSテーブルでUPDATEトリガーを作成します。
        CREATE TRIGGER TR_GUESTS_AUDIT ON GUESTS FOR UPDATE
        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)
               
        
        --You will need to change @TableName to match the table to be audited. 
        -- Here we made GUESTS for your example.
        SELECT @TableName = 'GUESTS'
        
        -- 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
        
        GO
    


    1. MySQLでは列名とテーブル名で大文字と小文字が区別されますか?

    2. 接続プールを使用したPostgreSQLでの接続のスケーリング

    3. 「アプリケーション「SQLDeveloper.app」を開くことができません。」を修正しました。

    4. PostgreSQL:PostgreSQLデータベースのユーザーにすべての権限を付与します