如何修复审核触发器,而不是捕获一列的更改

时间:2019-01-30 01:42:42

标签: sql sql-server database triggers

我有一个触发器来审核插入,删除和更新。为此,我已经修改了在线可用脚本。这些脚本无需任何修改即可很好地工作,但是对于业务需求,我进行了一些更改。对于我整个数据库中的9个表,此触发器具有自定义更改。触发器对于除1之外的所有8个表都运行良好。它给我发出的1个表仅适用于1列。

我的表包含以下列:

CREATE TABLE [d2c].[linkage_profile](
    [linkage_profile_id] [int] IDENTITY(1,1) NOT NULL Primary Key,
    [first_name] [nvarchar](250) NULL,
    [last_name] [nvarchar](250) NULL,
    [middle_name] [nvarchar](250) NULL,
    [suffix] [nvarchar](50) NULL,
    [is_pregnant] [bit] NULL,
    [expected_date] [datetime2](7) NULL,
    [user_id] [int] NOT NULL,
    [is_grace_period] [bit] NOT NULL,
    [closed_date] [datetime2](7) NULL,
    [birth_gender_id] [int] NOT NULL,
    [status_id] [int] NOT NULL,
    [assigned_date] [datetime2](7) NULL,
    [created_by] [nvarchar](50) NULL,
    [date_created] [datetime2](7) NOT NULL,
    [modified_by] [nvarchar](50) NULL,
    [date_modified] [datetime2](7) NULL,
    [state_no] [nvarchar](20) NULL,
    [county_id] [int] NULL,
    [area_name] [nvarchar](3) NULL,
    [ehars_client_profile_id] [int] NULL,
    [priority_id] [int] NULL,
    [assigned_by] [nvarchar](50) NULL,

这是我正在使用的触发器:

Alter TRIGGER [d2c].[tr_linkage_profile] ON d2c.linkage_profile FOR INSERT, UPDATE, DELETE

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(5000), 
@UpdateDate VARCHAR(21) ,
@UserName VARCHAR(128) ,
@Type CHAR(1) ,
@PKSelect VARCHAR(1000) ,
@linkageID VARCHAR(1000) ,
@FullTableName VARCHAR(256),
@oldvalue VARCHAR(1000),
@newvalue VARCHAR(1000),
@oldvalue1 VARCHAR(1000),
@newvalue1 VARCHAR(1000),
--@modified_by VARCHAR(20)='modified_by',
@isviewable char(1),
@next bit

SELECT @TableName = 'linkage_profile' , @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


-- 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
if @FullTableName <> 'd2c.ehars_client_profile'
BEGIN
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'
END

if @FullTableName = 'd2c.ehars_client_profile'
SELECT @linkageID = 'NULL'


IF @PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, @FullTableName)
RETURN
END
---------------------Display value for table
SET @TableDisplayName = 'Linkage Profile Data'

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


----
--select TABLE_NAME, COLUMN_NAME from  INFORMATION_SCHEMA.COLUMNS where TABLE_NAME in ('barrier_client',    'client_attempt','disposition', 'ehars_client_profile', 'note_attachement', 'linkage_profile',  'provider_attempt', 'referral_client',  'result')


--------------display values for fields
    SET @FieldDisplayName = CASE @fieldname --I have a lot of case statement here, removed to keep it short
            WHEN 'assigned_by' THEN 'Assigned By'
        WHEN 'assigned_date' THEN 'Assigned Date'
            END

-- Managing Is viewable field for all types
 select @isviewable = '0'
 ----------
 if @type in('U')
 begin
 select @isviewable = '1'
 end
 -----------
if @type in('D')
if @fieldname in ('referral_id','other_desc','barrier_id')
       Begin
                select @IsViewable='1'
       End
 -----------
if @fieldname  in ('created_by','date_created')
        Begin
                select @IsViewable='0'
       End
 -----------setting next at default 0
Select @next = 0
--------------------------------field specific values 5 Linkage Profile
        if @fieldname = 'User_ID'
            BEGIN
                select @oldvalue =c.first_name from [d2c].[user] c inner join deleted d on d.User_ID = c.User_ID
                select @oldvalue1 =c.last_name from [d2c].[user] c inner join deleted d on d.User_ID = c.User_ID
                Select @oldvalue = CONCAT (@oldvalue , ' ', @oldvalue1)
                if @oldvalue = 'd.expected_date '  set @oldvalue = 'NULL'

                select @newvalue = c.first_name from [d2c].[user] c inner join inserted i on i.User_ID = c.User_ID
                select @newvalue1 =c.last_name from [d2c].[user] c inner join inserted i on i.User_ID = c.User_ID
                Select @newvalue = CONCAT (@newvalue , ' ', @newvalue1)
                if @newvalue = 'i.expected_date '  set @newvalue = 'NULL'
                Select @next = 1

            end

        if @fieldname = 'birth_gender_id'
            BEGIN
                select @oldvalue =c.name from lu.birth_gender c inner join deleted d on d.birth_gender_id = c.birth_gender_id
                if @oldvalue = 'd.closed_date'  set @oldvalue = 'NULL'

                select @newvalue = c.name from lu.birth_gender c inner join inserted i on i.birth_gender_id = c.birth_gender_id
                if @newvalue = 'i.closed_date'  set @newvalue = 'NULL'
                Select @next = 1

            end

        if @fieldname = 'Status_ID'
            BEGIN
                select @oldvalue =c.status_name from lu.status c inner join deleted d on d.Status_ID = c.Status_ID
                if @oldvalue = 'd.closed_date'  set @oldvalue = 'NULL'

                select @newvalue = c.status_name from lu.status c inner join inserted i on i.Status_ID = c.Status_ID
                if @newvalue = 'i.closed_date'  set @newvalue = 'NULL'
                Select @next = 1

            end
            if @fieldname = 'county_id'
            BEGIN
                select @oldvalue =c.name from lu.county c inner join deleted d on d.county_id = c.county_id
                if @oldvalue = 'd.state_no'  set @oldvalue = 'NULL'

                select @newvalue = c.name from lu.county c inner join inserted i on i.county_id = c.county_id
                if @newvalue = 'i.state_no'  set @newvalue = 'NULL'
                Select @next = 1

            end

                if @fieldname = 'priority_id'
            BEGIN
                select @oldvalue =c.priority_name from lu.priority c inner join deleted d on d.priority_id = c.priority_id
                if @oldvalue = 'd.ehars_client_profile_id'  set @oldvalue = 'NULL'

                select @newvalue = c.priority_name from lu.priority c inner join inserted i on i.priority_id = c.priority_id
                if @newvalue = 'i.ehars_client_profile_id'  set @newvalue = 'NULL'
                Select @next = 1

            end

--------------------------------------------------------------------------running field specific value in insert
    If @next = 1

    if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in ('I','D')
    print substring(COLUMNS_UPDATED(),@char, 1);
        BEGIN
        SELECT @sql = '
        insert d2c.Audit_client_Data ( 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

--------------------condition 1 change this for each trigger

if  @next = 0 
if @fieldname not in ('modified_by','date_modified')
        if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in ('I','D')

            BEGIN

                select @oldvalue ='d.'+@fieldname
                select @newvalue = 'i.'+@fieldname
                SELECT @sql = '
                insert d2c.Audit_client_Data ( 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

当我更新,插入或删除所有列时,触发器将处理除最后一列Assigned_by以外的所有内容。我无法找出问题所在。它没有通过此代码

"if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in ('I','D')" which is at the very bottom. HELP!!! 

0 个答案:

没有答案