noodle22
Programmer
- May 8, 2008
- 23
Hi,
I've created a change log for when data in a table changes (I'm actually using it for a wiki type app). I have two ways of doing this
a) copy all the new data and all the old data into the change log table
b) copy only the changes
The advantage of (a) is that it doesn't compare anything and just spits all the old and new data into a change log table. Unfortunately, lots of data that doesn't need to be copied will be if only a small change takes place,
The advantage of (b) is that only the changes are copied. The disadvantage is that for updates only, I have to compare all the fields from the inserted and deleted to see if they are changed (so, I almost need a really fast equals comparison...although, maybe an equals comparison already is pretty fast), use dynamic sql, copy inserted/deleted into temp tables
So, here is the code. I'm sure it is useful for other projects but I still don't know which method to use. I just put a trigger on the tables that I need to track (there are only a small number of these tables
Method A
And here is method b
I've created a change log for when data in a table changes (I'm actually using it for a wiki type app). I have two ways of doing this
a) copy all the new data and all the old data into the change log table
b) copy only the changes
The advantage of (a) is that it doesn't compare anything and just spits all the old and new data into a change log table. Unfortunately, lots of data that doesn't need to be copied will be if only a small change takes place,
The advantage of (b) is that only the changes are copied. The disadvantage is that for updates only, I have to compare all the fields from the inserted and deleted to see if they are changed (so, I almost need a really fast equals comparison...although, maybe an equals comparison already is pretty fast), use dynamic sql, copy inserted/deleted into temp tables
So, here is the code. I'm sure it is useful for other projects but I still don't know which method to use. I just put a trigger on the tables that I need to track (there are only a small number of these tables
Method A
Code:
CREATE TRIGGER [dbo].[TableName_HISChanges]
ON [dbo].TableName
FOR UPDATE, DELETE, INSERT AS
BEGIN
SET NOCOUNT ON;
DECLARE @Action VARCHAR(6)
DECLARE @inserted VARCHAR(MAX)
DECLARE @deleted VARCHAR(MAX)
SET @Action = 'UPDATE'
SET @inserted = (SELECT * FROM inserted as TableName FOR XML AUTO, ELEMENTS)
SET @deleted = (SELECT * FROM deleted as TableName FOR XML AUTO, ELEMENTS)
IF @inserted IS NULL
SET @Action = 'DELETE'
IF @deleted IS NULL
SET @Action = 'INSERT'
IF ((NOT @inserted IS NULL) OR (NOT @deleted IS NULL))
INSERT INTO HIS_TableName(CommandType,Changes, OldData) VALUES
(@Action, @inserted,@deleted )
END
And here is method b
Code:
CREATE TRIGGER [dbo].[trig_HISTableName2]
ON [dbo].TableName
FOR UPDATE, DELETE, INSERT AS
BEGIN
SET NOCOUNT ON;
DECLARE @Action VARCHAR(6)
DECLARE @inserted VARCHAR(MAX)
DECLARE @deleted VARCHAR(MAX)
DECLARE @InsertCount INT
DECLARE @DeleteCount INT
DECLARE @Xml VARCHAR(MAX)
DECLARE @SQL NVARCHAR(MAX)
SELECT @InsertCount = Count(*) FROM inserted
SELECT @DeleteCount = Count(*) FROM deleted
IF @InsertCount = 0
BEGIN
SET @Action = 'DELETE'
SET @Xml = (SELECT * FROM deleted as TableName FOR XML AUTO, ELEMENTS)
END
ELSE IF @DeleteCount = 0
BEGIN
SET @Action = 'INSERT'
SET @Xml = (SELECT * FROM inserted as TableName FOR XML AUTO, ELEMENTS)
END
ELSE
BEGIN
SET @Action = 'UPDATE'
DECLARE @compareFields VARCHAR(MAX)
SET @compareFields =
( SELECT
CASE
WHEN NOT cu.COLUMN_NAME IS NULL THEN --is a primary key, we need this column
'''<PKColumn Name="' + c.Column_Name + '">'' + CAST(i.' + c.Column_Name + ' AS VARCHAR(MAX)) + ''</PKColumn>'' + '
ELSE --just a regular column that might have been changed
'CASE WHEN d.' + c.Column_Name + ' != i.' + c.Column_Name +
' THEN ''<column name="' + c.Column_Name + '"><new>'' + CAST(i.'+ c.Column_Name + ' as VARCHAR(MAX)) + ''</new><old>'' + CAST(d.' + c.Column_Name + ' as VARCHAR(MAX)) + ''</old></column>''ELSE '''' END+'
END
FROM
--Get the Column Names
INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu
INNER JOIN
INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk
ON
cu.CONSTRAINT_NAME = pk.CONSTRAINT_NAME AND
cu.TABLE_NAME = pk.TABLE_NAME AND
pk.CONSTRAINT_TYPE = 'PRIMARY KEY'
RIGHT OUTER JOIN
INFORMATION_SCHEMA.COLUMNS c
ON cu.COLUMN_NAME = c.COLUMN_NAME AND
c.TABLE_NAME = cu.TABLE_NAME
WHERE c.TABLE_NAME = 'TableName'
FOR XML PATH('')
) + ' '''' '
SET @compareFields = REPLACE(@compareFields,'<','<')
SET @compareFields = REPLACE(@compareFields,'>','>')
SELECT * INTO #deleted FROM deleted
SELECT * INTO #inserted FROM inserted
SET @SQL = 'SELECT @Xml=' + @compareFields + ' FROM #inserted i
INNER JOIN
#deleted d ON i.CourseID = d.CourseID
'
EXEC sp_executesql @SQL,N'@Xml VARCHAR(MAX) OUT', @Xml OUT
END
INSERT INTO HIS_TableName2(CommandType,Changes) VALUES
(@Action, @Xml)
END