SQL Server Update Trigger, Get Only modified fields

前端 未结 8 1204
旧巷少年郎
旧巷少年郎 2020-11-29 03:44

I am aware of COLUMNS_UPDATED, well I need some quick shortcut (if anyone has made, I am already making one, but if anyone can save my time, I will appriciate i

相关标签:
8条回答
  • 2020-11-29 04:19

    The only way that occurs to me that you could accomplish this without hard coding column names would be to drop the contents of the deleted table to a temp table, then build a query based on the table definition to to compare the contents of your temp table and the actual table, and return a delimited column list based on whether they do or do not match. Admittedly, the below is elaborate.

    Declare @sql nvarchar(4000)
    DECLARE @ParmDefinition nvarchar(500)
    Declare @OutString varchar(8000)
    Declare @tbl sysname
    
    Set @OutString = ''
    Set @tbl = 'SomeTable' --The table we are interested in
    --Store the contents of deleted in temp table
    Select * into #tempDelete from deleted 
    --Build sql string based on definition 
    --of table 
    --to retrieve the column name
    --or empty string
    --based on comparison between
    --target table and temp table
    set @sql = ''
    Select @sql = @sql + 'Case when IsNull(i.[' + Column_Name + 
    '],0) = IsNull(d.[' + Column_name + '],0) then '''' 
     else ' + quotename(Column_Name, char(39)) + ' + '',''' + ' end +'
    from information_schema.columns 
    where table_name = @tbl
    --Define output parameter
    set @ParmDefinition = '@OutString varchar(8000) OUTPUT'
    --Format sql
    set @sql = 'Select @OutString = ' 
    + Substring(@sql,1 , len(@sql) -1) + 
    ' From SomeTable i  ' --Will need to be updated for target schema
    + ' inner join #tempDelete d on
    i.PK = d.PK ' --Will need to be updated for target schema
    --Execute sql and retrieve desired column list in output parameter
    exec sp_executesql @sql, @ParmDefinition, @OutString OUT
    drop table  #tempDelete
    --strip trailing column if a non-zero length string 
    --was returned
    if Len(@Outstring) > 0 
        Set @OutString = Substring(@OutString, 1, Len(@Outstring) -1)
    --return comma delimited list of changed columns. 
    Select @OutString 
    End
    
    0 讨论(0)
  • 2020-11-29 04:26

    The sample code provided by Rick lack handling for multiple rows update.

    Please let me enhance Rick's version as below:

    USE [AFC]
    GO
    
    /****** Object:  Trigger [dbo].[trg_Survey_Identify_Updated_Columns]    Script Date: 27/7/2018 14:08:49 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    ALTER TRIGGER [dbo].[trg_Survey_Identify_Updated_Columns] ON [dbo].[Sample_Table] --Change to match your table name
    FOR INSERT
    	,UPDATE
    AS
    SET NOCOUNT ON;
    
    DECLARE @sql VARCHAR(5000)
    	,@sqlInserted NVARCHAR(500)
    	,@sqlDeleted NVARCHAR(500)
    	,@NewValue NVARCHAR(100)
    	,@OldValue NVARCHAR(100)
    	,@UpdatedBy VARCHAR(50)
    	,@ParmDefinitionD NVARCHAR(500)
    	,@ParmDefinitionI NVARCHAR(500)
    	,@TABLE_NAME VARCHAR(100)
    	,@COLUMN_NAME VARCHAR(100)
    	,@modifiedColumnsList NVARCHAR(4000)
    	,@ColumnListItem NVARCHAR(500)
    	,@Pos INT
    	,@RecordPk VARCHAR(50)
    	,@RecordPkName VARCHAR(50);
    
    SELECT *
    INTO #deleted
    FROM deleted;
    
    SELECT *
    INTO #Inserted
    FROM inserted;
    
    SET @TABLE_NAME = 'Sample_Table';---Change to your table name
    
    DECLARE t_cursor CURSOR
    FOR
    SELECT ContactID 
    FROM inserted
    
    OPEN t_cursor
    
    FETCH NEXT
    FROM t_cursor
    INTO @RecordPk 
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    	--SELECT @UpdatedBy = Surname --Change to your column name for the user update field
    	--FROM inserted;
    	--SELECT @RecordPk = ContactID --Change to the table primary key field
    	--FROM inserted;
    	SET @RecordPkName = 'ContactID';
    	SET @modifiedColumnsList = STUFF((
    				SELECT ',' + name
    				FROM sys.columns
    				WHERE object_id = OBJECT_ID(@TABLE_NAME)
    					AND SUBSTRING(COLUMNS_UPDATED(), ((column_id - 1) / 8 + 1), 1) & (POWER(2, ((column_id - 1) % 8 + 1) - 1)) = POWER(2, (column_id - 1) % 8)
    				FOR XML PATH('')
    				), 1, 1, '');
    
    	WHILE LEN(@modifiedColumnsList) > 0
    	BEGIN
    		SET @Pos = CHARINDEX(',', @modifiedColumnsList);
    
    		IF @Pos = 0
    		BEGIN
    			SET @ColumnListItem = @modifiedColumnsList;
    		END;
    		ELSE
    		BEGIN
    			SET @ColumnListItem = SUBSTRING(@modifiedColumnsList, 1, @Pos - 1);
    		END;
    
    		SET @COLUMN_NAME = @ColumnListItem;
    		SET @ParmDefinitionD = N'@OldValueOut NVARCHAR(100) OUTPUT';
    		SET @ParmDefinitionI = N'@NewValueOut NVARCHAR(100) OUTPUT';
    		SET @sqlDeleted = N'SELECT @OldValueOut=' + @COLUMN_NAME + ' FROM #deleted where ' + @RecordPkName + '=' + CONVERT(VARCHAR(50), @RecordPk);
    		SET @sqlInserted = N'SELECT @NewValueOut=' + @COLUMN_NAME + ' FROM #Inserted where ' + @RecordPkName + '=' + CONVERT(VARCHAR(50), @RecordPk);
    
    		EXECUTE sp_executesql @sqlDeleted
    			,@ParmDefinitionD
    			,@OldValueOut = @OldValue OUTPUT;
    
    		EXECUTE sp_executesql @sqlInserted
    			,@ParmDefinitionI
    			,@NewValueOut = @NewValue OUTPUT;
    
    		--PRINT @newvalue
    		--PRINT @oldvalue
    
    		IF (LTRIM(RTRIM(@NewValue)) != LTRIM(RTRIM(@OldValue)))
    		BEGIN
    			SET @sql = 'INSERT INTO [dbo].[AuditDataChanges]
                                                   ([TableName]
                                                   ,[RecordPK]
                                                   ,[ColumnName]
                                                   ,[OldValue]
                                                   ,[NewValue] )
                                             VALUES
                                                   (' + QUOTENAME(@TABLE_NAME, '''') + '
                                                   ,' + QUOTENAME(@RecordPk, '''') + '
                                                   ,' + QUOTENAME(@COLUMN_NAME, '''') + '
                                                   ,' + QUOTENAME(@OldValue, '''') + '
                                                   ,' + QUOTENAME(@NewValue, '''') + '
                                                   '  + ')';
    
    			EXEC (@sql);
    		END;
    
    		SET @COLUMN_NAME = '';
    		SET @NewValue = '';
    		SET @OldValue = '';
    
    		IF @Pos = 0
    		BEGIN
    			SET @modifiedColumnsList = '';
    		END;
    		ELSE
    		BEGIN
    			-- start substring at the character after the first comma
    			SET @modifiedColumnsList = SUBSTRING(@modifiedColumnsList, @Pos + 1, LEN(@modifiedColumnsList) - @Pos);
    		END;
    	END;
    
    	FETCH NEXT
    	FROM t_cursor
    	INTO @RecordPk 
    END
    
    DROP TABLE #Inserted;
    
    DROP TABLE #deleted;
    
    CLOSE t_cursor;
    
    DEALLOCATE t_cursor;

    0 讨论(0)
提交回复
热议问题