数据库审核触发器

时间:2019-01-03 20:32:07

标签: sql-server tsql database-trigger audit

我对数据库表有一个审计触发器,这是从在线文章中获得的。触发器效果很好,但是我想根据需要自定义它。我被困在一个地方,需要帮助。我对此并不陌生,所以这可能是一个简单的问题。

ALTER TRIGGER [d2c].[tr_referral_client] ON [d2c].[referral_client] FOR 
UPDATE, DELETE, Insert
AS
SET NOCOUNT ON
    DECLARE @bit INT ,
    @field INT ,
    @fieldId INT ,
    @maxfield INT ,
    @char INT ,
    @fieldname VARCHAR(128) ,
    @FieldDisplayName VARCHAR(128),
    @TableDisplayName VARCHAR(128),
    @SchemaName VARCHAR(128) ,
    @TableName VARCHAR(128) ,
    @PKCols VARCHAR(1000) ,
    @sql VARCHAR(2000), 
    @UpdateDate VARCHAR(21) ,
    @UserName VARCHAR(128) ,
    @Type CHAR(1) ,
    @PKSelect VARCHAR(1000) ,
    @linkageID VARCHAR(1000) ,
    @FullTableName VARCHAR(256),
    @oldvalue VARCHAR(1000),
    @newvalue VARCHAR(1000),
    @modified_by VARCHAR(20)='modified_by',
    @isviewable char(1)

    --You will need to change @TableName to match the table to be audited
    SELECT @TableName = 'referral_client', @SchemaName = 'd2c'

    SELECT @FullTableName = @SchemaName + '.' + @TableName

    -- date and user
    SELECT @UserName = SYSTEM_USER ,
    @UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112) 
    + ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)

    -- 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

     if @type in('U','D')
     select @isviewable = '1'
     else
     select @isviewable = '0'

    -- 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 pk.TABLE_SCHEMA = @SchemaName
    AND CONSTRAINT_TYPE = 'PRIMARY KEY'
    AND c.TABLE_NAME = pk.TABLE_NAME
    AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
    AND c.CONSTRAINT_SCHEMA = pk.TABLE_SCHEMA

    -- Get primary key select for insert
    SELECT @PKSelect = COALESCE(@PKSelect+'+','') + '''' +
     '''+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 pk.TABLE_SCHEMA = @SchemaName
    AND CONSTRAINT_TYPE = 'PRIMARY KEY'
    AND c.TABLE_NAME = pk.TABLE_NAME
    AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
    AND c.CONSTRAINT_SCHEMA = pk.TABLE_SCHEMA

    -- Get client id select for insert
    SELECT @linkageID = COALESCE(@linkageID+'+','') + '''' + 
     '''+convert(varchar(100),coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''''' 
    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
    WHERE c.TABLE_NAME = @TableName
    AND c.TABLE_SCHEMA = @SchemaName
    AND c.COLUMN_NAME = 'linkage_profile_id'

    IF @PKCols IS NULL
    BEGIN
    RAISERROR('no PK on table %s', 16, -1, @FullTableName)
    RETURN
    END

    ---------------------Display value for table
    SET @TableDisplayName = CASE @TableName
           WHEN 'referral_client' THEN 'Referrals'
        END
    --------------------------
    SELECT @field = 0, 
    @maxfield = MAX(ORDINAL_POSITION) 
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName AND TABLE_SCHEMA = @SchemaName

    WHILE @field < @maxfield
    BEGIN
    SELECT @fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS 
        WHERE TABLE_NAME = @TableName
        AND TABLE_SCHEMA = @SchemaName
        AND ORDINAL_POSITION = @field

    SELECT @fieldid = COLUMNPROPERTY(OBJECT_ID(@FullTableName), @fieldname, 'ColumnID')

    SELECT @field = MIN(ORDINAL_POSITION) 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = @TableName 
    AND TABLE_SCHEMA = @SchemaName
    AND ORDINAL_POSITION > @field
    select @bit = (@fieldid - 1 )% 8 + 1
    select @bit = power(2,@bit - 1)
    select @char = ((@fieldid - 1) / 8) + 1

    --------------------getting referral values
    if @fieldname in ('referral_id')
    begin
    select @oldvalue = c.referral_name
    from lu.referral c inner join deleted d
    on d.referral_id = c.referral_id

    select @newvalue = c.referral_name
    from lu.referral c inner join inserted i
    on i.referral_id = c.referral_id
    end
    -------------------------

    if @fieldname NOT in ('referral_id')
    begin
    select @oldvalue ='Code here'====================================>>
    --convert(varchar(1000),d.' + @fieldname + ')'+ ',

    Select @newvalue = 'Code here'==================================>>
    --convert(varchar(1000),i.' + @fieldname + ')'+ ',

    END
    ------------------
    if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in ('I','D')
        if @fieldname not in ('modified_by','date_modified')
            --------------display values for fields
        SET @FieldDisplayName = CASE @fieldname
           WHEN 'referral_client_id' THEN 'Referral ID'
           WHEN 'linkage_profile_id' THEN 'Linkage Profile ID'
           WHEN 'referral_id' THEN 'Referral Name'
           WHEN 'other_desc' THEN 'Other Description'
           WHEN 'Created_by' THEN 'Record Created By'
           WHEN 'Date_created' THEN 'Record Creation Date'
           WHEN 'Modified_by' THEN 'Record Last Modified By'
           WHEN 'date_modified' THEN 'Record Last Modified Date'
        END
    ---------------------------

    BEGIN

    SELECT @sql = '
    insert d2c.Audit ( Type,
    TableSchema,
    TableName,
    tabledisplayname,
    fielddisplayname, 
    PK, 
    linkage_profile_id,
    is_viewable,
    FieldName, 
    OldValue, 
    NewValue, 
    UpdateDate, 
    UserName,
    Application
    )
    select ''' + @Type + ''',
    ''' + @SchemaName + ''',
    ''' + @TableName + ''',
    ''' + @TableDisplayName + ''',
    ''' + @FieldDisplayName + ''',
    ' + @PKSelect+ ',
    ' + @linkageID+ ',
     '+ @isviewable+' ,
    ''' + @fieldname + ''''+ ',' + @oldvalue + ',
    ' + @newvalue + ',
    ''' + @UpdateDate + ''''+ ',

    ''' + @UserName + '''' + ',

    ''' + REPLACE(APP_NAME(), '''', '''''') + '''' 
           + ' 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

这是我正在使用的触发器。在插入时,使用以下代码插入了更改后的值在审计表中,旧值和新值:-convert(varchar(1000),d.' + @fieldname + ')'+ ',用于删除,--convert(varchar(1000),i.' + @fieldname + ')'+ ',用于插入。

由于我需要修改特定列的值,因此添加了if语句,并使用@oldvalue@newvalue生成所需的内容,然后将其传递给insert语句。

对于一次性列,我获得了正确的值,但是对于其余列,当我尝试使用上述代码时,我将相同的字符串插入到审计表中。请帮忙!

我可以回答您可能遇到的任何问题。

0 个答案:

没有答案