Average 28000 requests/month












 

/*
Created 29th Jan 2007: PI
Explanation: Modification of Nigel's excellent script for audit triggers. Changed in various ways including use of environmental variables, using a direct comparison of columns in the updated trigger and the use of XML text for auditing.
This trigger will place all details in the table called "Audit".
The batch will produce an error message if there is no primary key on the source table.
You just will need to change the environmental variable to match the table to be audit for a singleton or use the parent script "AddAllTriggers.sql" to iterate through all your tables.
*/

--:setvar tablename Project

if exists (select * from sys.triggers where name = 'tr_Audit_Update_$(tablename)')
drop trigger tr_Audit_Update_$(tablename)
if exists (select * from sys.triggers where name = 'tr_Audit_Delete_$(tablename)')
drop trigger tr_Audit_Delete_$(tablename)
if exists (select * from sys.triggers where name = 'tr_Audit_Insert_$(tablename)')
drop trigger tr_Audit_Insert_$(tablename)
go

create trigger tr_Audit_Update_$(tablename) on $(tablename) for update
as

declare @field int ,
@maxfield int ,
@fieldname varchar(128) ,
@sql varchar(max),
@UpdateDate varchar(100) ,
@UserID int ,
@UserName varchar(200),
@PKColumn varchar(1000),
@ParmDefinition nvarchar(2000),
@fieldvalueINS_sql varchar(max),
@fieldvalueDEL_sql varchar(max),
@fieldvalueINS varchar(max),
@fieldvalueDEL varchar(max),
@count int,
@totalrowcount int,
@Audit_Details varchar(max),
@SQLString nvarchar(max)

-- date and user
set @UserID = isnull((select top (1) Last_Updated_By from inserted),'')
set @UserName = isnull((select isnull(forename,'') + ' ' + isnull(surname,'') from dbo.TESA_User where [User_ID] = @UserID),'N/A')
set @UpdateDate = convert(varchar(100), getdate(), 113)

-- get list of columns and add a final column for the recordcount
select *, 99999 as RecordCount into #ins from inserted
select * into #del from deleted

-- now I need to populate the recordcount column to use as a reference rowcount
-- can't use identity column as there will already be one

set @totalrowcount = (select count(*) from #ins)
set @count = 1
while @count <= @totalrowcount
begin
update top (1) #ins set RecordCount = @count where RecordCount > @count
set @count = @count + 1
end

-- Get primary key column to be able to stipulate the join
select @PKColumn = 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 @PKColumn is null
begin
raiserror('no PK on table $(tablename)', 16, -1)
return
end

select @maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)'

-- iterate through the rows here
declare @loopcount int
declare @character_maximum_length int
set @loopcount = 1
while @loopcount <= @totalrowcount
begin
select @field = 0
set @sql = ''
set @Audit_Details = '<audit>' + char(10) + char(13)
set @Audit_Details = @Audit_Details + '<table TableName="$(tablename)" ChangeDate="' + @UpdateDate + '" UserName="' + @UserName +'">'

-- iterate through the fields here
while @field < @maxfield
begin
select @field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)' and ORDINAL_POSITION > @field
select @fieldname = '[' + COLUMN_NAME + ']', @character_maximum_length = isnull(character_maximum_length,0) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)' and ORDINAL_POSITION = @field
set @SQLString = 'Select top 1 '
set @SQLString = @SQLString + '@fieldvalueINS_sql = cast(i.' + @fieldname + ' as varchar(max)), '
set @SQLString = @SQLString + '@fieldvalueDEL_sql = cast(d.' + @fieldname + ' as varchar(max)) '
set @SQLString = @SQLString + 'from #ins i inner join #del d on i.' + @PKColumn + ' = d.' + @PKColumn
set @SQLString = @SQLString + ' where RecordCount = ' + cast(@loopcount as varchar(100))
set @ParmDefinition = N'@fieldvalueINS_sql varchar(max) output,'
set @ParmDefinition = @ParmDefinition + N'@fieldvalueDEL_sql varchar(max) output';

exec sp_executesql @SQLString, @ParmDefinition,@fieldvalueINS_sql = @fieldvalueINS OUTPUT, @fieldvalueDEL_sql = @fieldvalueDEL OUTPUT; --, @fieldvaluePK_sql = @fieldvaluePK OUTPUT;
if (isnull(@fieldvalueINS,'xxx123') <> isnull(@fieldvalueDEL,'xxx123')) or ('[' + @PKColumn + ']' = @fieldname) -- values are different or we have the PK column
begin
set @Audit_Details = @Audit_Details + '<column ColumnName="' + @fieldname + '" InsertedValue="' + isnull(replace(@fieldvalueINS,'''',''''''),'[NULL]') + '" DeletedValue="' + isnull(replace(@fieldvalueDEL,'''',''''''),'[NULL]') + '"/> ' + char(10) + char(13)
end

end

set @Audit_Details = @Audit_Details + '</table>' + char(10) + char(13)
set @Audit_Details = @Audit_Details + '</audit>'

-- make the audit insert for this row
select @sql = 'insert Audit (Audit_Operation, Audit_TableName, Audit_Details, UpdateDate, UserName)'
select @sql = @sql + ' select ''Update'''
select @sql = @sql + ',''$(tablename)'''
select @sql = @sql + ',''' + @Audit_Details + ''''
select @sql = @sql + ',''' + @UpdateDate + ''''
select @sql = @sql + ',''' + @UserName + ''''
exec (@sql)

set @loopcount = @loopcount + 1
end
go

create trigger tr_Audit_Insert_$(tablename) on $(tablename) for Insert
as
declare @bit int ,
@field int ,
@maxfield int ,
@char int ,
@fieldname varchar(128) ,
@sql varchar(max),
@InsertDate varchar(100) ,
@UserID int,
@UserName varchar(200),
@IntVariable int,
@SQLString nvarchar(max),
@ParmDefinition nvarchar(500),
@fieldname_sql varchar(1000),
@fieldvalue varchar(max),
@Audit_Details varchar(max),
@RowCounter int,
@totalInserted int,
@character_maximum_length int

set @Audit_Details = ''
set @RowCounter = 1
set @totalInserted = (select count(*) from inserted)

-- date and user
set @UserID = isnull((select top (1) Created_By from inserted),'')
set @UserName = isnull((select isnull(forename,'') + ' ' + isnull(surname,'') from dbo.TESA_User where [User_ID] = @UserID),'N/A')
set @InsertDate = convert(varchar(100), getdate(), 113)

-- get list of rows. We'll remove these one by one as they are audited
select * into #ins from inserted
select @maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)'

-- iterate through the inserted rows. Normally this'll be one row only, but we can't guarantee this
while @RowCounter <= @totalInserted
begin
select @field = 0
set @sql = ''
set @Audit_Details = '<audit>' + char(10) + char(13)
set @Audit_Details = @Audit_Details + '<table TableName="$(tablename)" ChangeDate="' + @InsertDate + '" UserName="' + @UserName +'">'
--select @Audit_Details
-- iterate through the fields
while @field < @maxfield
begin
select @field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)' and ORDINAL_POSITION > @field
select @fieldname = '[' + COLUMN_NAME + ']', @character_maximum_length = isnull(character_maximum_length,0) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)' and ORDINAL_POSITION = @field
if @character_maximum_length <> -1
begin
set @SQLString = 'Select top 1 @fieldvalue_sql = cast(' + @fieldname + ' as varchar(max)) from #ins i'
set @ParmDefinition = '@fieldvalue_sql varchar(max) output';
exec sp_executesql @SQLString, @ParmDefinition,@fieldvalue_sql = @fieldvalue OUTPUT;
set @Audit_Details = @Audit_Details + '<column ColumnName="' + @fieldname + '" InsertedValue="' + isnull(replace(@fieldvalue,'''',''''''),'[NULL]') + '"/> ' + char(10) + char(13)
end
end

set @Audit_Details = @Audit_Details + '</table>' + char(10) + char(13)
set @Audit_Details = @Audit_Details + '</audit>'

-- make the audit insert for this row
select @sql = 'insert Audit (Audit_Operation, Audit_TableName, Audit_Details, UpdateDate, UserName)'
select @sql = @sql + ' select ''Insert'''
select @sql = @sql + ',''$(tablename)'''
select @sql = @sql + ',''' + @Audit_Details + ''''
select @sql = @sql + ',''' + @InsertDate + ''''
select @sql = @sql + ',''' + @UserName + ''''

exec (@sql)

--remove the one we just added
delete top(1) from #ins
set @RowCounter = @RowCounter + 1
end
go

create trigger tr_Audit_Delete_$(tablename) on $(tablename) for Delete
as
declare @bit int ,
@field int ,
@maxfield int ,
@char int ,
@fieldname varchar(128) ,
@sql varchar(max),
@DeleteDate varchar(100) ,
@UserID int,
@UserName varchar(200),
@IntVariable int,
@SQLString nvarchar(max),
@ParmDefinition nvarchar(500),
@fieldname_sql varchar(1000),
@fieldvalue varchar(max),
@Audit_Details varchar(max),
@RowCounter int,
@totalDeleted int,
@character_maximum_length int

set @Audit_Details = ''
set @RowCounter = 1
set @totalDeleted = (select count(*) from Deleted)
-- date and user
set @UserID = isnull((select top (1) Last_Updated_By from Deleted),'')
set @UserName = isnull((select isnull(forename,'') + ' ' + isnull(surname,'') from dbo.TESA_User where [User_ID] = @UserID),'N/A')
set @DeleteDate = convert(varchar(100), getdate(), 113)
-- get list of rows. We'll remove these one by one as they are audited
select * into #del from Deleted
select @maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)'
-- iterate through the inserted rows. Normally this'll be one row only, but we can't guarantee this
while @RowCounter <= @totalDeleted
begin
select @field = 0
set @sql = ''
set @Audit_Details = '<audit>' + char(10) + char(13)
set @Audit_Details = @Audit_Details + '<table TableName="$(tablename)" ChangeDate="' + @DeleteDate + '" UserName="' + @UserName +'">'

-- iterate through the fields
while @field < @maxfield
begin
select @field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)' and ORDINAL_POSITION > @field
select @fieldname = '[' + COLUMN_NAME + ']', @character_maximum_length = isnull(character_maximum_length,0) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '$(tablename)' and ORDINAL_POSITION = @field
if @character_maximum_length <> -1
begin
set @SQLString = 'Select top 1 @fieldvalue_sql = cast(' + @fieldname + ' as varchar(max)) from #del d'
set @ParmDefinition = '@fieldvalue_sql varchar(max) output';
exec sp_executesql @SQLString, @ParmDefinition, @fieldvalue_sql = @fieldvalue OUTPUT;
set @Audit_Details = @Audit_Details + '<column ColumnName="' + @fieldname + '" DeletedValue="' + isnull(replace(@fieldvalue,'''',''''''),'[NULL]') + '"/> ' + char(10) + char(13)
end
end

set @Audit_Details = @Audit_Details + '</table>' + char(10) + char(13)
set @Audit_Details = @Audit_Details + '</audit>'

-- make the audit insert for this row
select @sql = 'insert Audit (Audit_Operation, Audit_TableName, Audit_Details, UpdateDate, UserName)'
select @sql = @sql + ' select ''Delete'''
select @sql = @sql + ',''$(tablename)'''
select @sql = @sql + ',''' + @Audit_Details + ''''
select @sql = @sql + ',''' + @DeleteDate + ''''
select @sql = @sql + ',''' + @UserName + ''''

exec (@sql)

--remove the one we just added
delete top(1) from #del
set @RowCounter = @RowCounter + 1
end
go

 

 
 

July 2005