Thursday, July 12, 2012

audit storeproc

Here is a good storeproc to audit your database tables for changes

first create table for your audit list

****** Object: Table [dbo].[Auditlist] Script Date: 07/12/2012 15:10:35 ******/ ANSI_NULLS ON QUOTED_IDENTIFIER ON ANSI_PADDING ON TABLE [dbo].[Auditlist]([sz30tablename] [varchar]
)
(128) NOT NULL ON [PRIMARY]GO
SET
GO
ANSI_PADDING OFF

then insert into this the tables you want to audit

insert into auditlist values ('tablename')

then create the proc

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_addaudittable]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[sp_addaudittable]
GO
USE [databasename]
GO
/****** Object:  StoredProcedure [dbo].[sp_addaudittable]    Script Date: 07/12/2012 14:46:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

create proc [dbo].[sp_addaudittable] @tablename varchar(40)
as
declare @databasename varchar(30)
declare @status  smallint
declare @statement varchar(8000)
declare @id  int
declare @audittable char(50)
declare @identity  tinyint
set nocount on
 if not exists(select name from sysobjects where name = 'Auditlist' and type = 'U')
 begin
  print '--Auditlist table does not exist'
  return 1
 end
 if not exists(select name from sysobjects where name = @tablename and type = 'U' and uid = 1)
 begin
  print '--Source table does not exist'
  return 1
 end
 if not exists(select sz30tablename from dbo.auditlist where sz30tablename = @tablename)
  insert into dbo.auditlist (sz30tablename) values (@tablename)
 if exists(select name from sysobjects where name like @tablename + '_a' and type = 'U' and uid = 1)
 begin
  print '--Audit table already exists - please drop first'
  return 1
 end
 if exists(select name from sysobjects where name like @tablename + '_a' and type = 'U' and uid <> 1)
 begin
  print '--Invalid audit table. Not dbo.'
  return 1
 end
 SELECT @databasename = db_name(),@audittable = @tablename+'_a'
 SELECT  @status = (status & 4)
 FROM master..sysdatabases
 WHERE name = db_name()
 if @status = 0
 begin
  exec sp_dboption @databasename, 'select into/bulkcopy',TRUE
 end
 if exists(
 SELECT  *
 FROM  syscolumns
 WHERE  (status & 128) = 128 and
  object_name(id) = @tablename )
  SET @identity = 1
 else
  SET @identity = 0
 if @identity = 0
  SET @statement = 'select * into ' + 'dbo.' + @tablename + '_a from ' + @tablename + ' where 1>2'
 else
  SET @statement = 'select t1.* into ' + 'dbo.' + @tablename + '_a from ' + @tablename + ' t1 join ' + @tablename + ' t2 on t1.identitycol = t2.identitycol where 1>2'
 execute (@statement)
 SELECT @statement = 'alter table dbo.'+ @tablename + '_a ' + 'add sz30auditusername varchar(30) null, sz1auditType char(1) null, sz30audithostname char(30) null, dtaudittimestamp datetime null'
 execute (@statement)
 -- Now we need to get rid of the timestamp column
 declare @TimestampColname varchar(100)

 SELECT @TimestampColname = syscolumns.name
 FROM  syscolumns
 JOIN  systypes on syscolumns.xusertype = systypes.xusertype
 WHERE  systypes.name like 'Timestamp' and id = object_id(@tablename)

 if @@rowcount > 0
 begin
  SET @statement = 'alter table dbo.' + @tablename + '_a drop column ' + @TimestampColname
  exec(@statement)
 end
 -- Now get a list of columns
 declare @cols table (colid int, colname varchar(100))
 INSERT
 INTO @cols
 SELECT  colid,
  syscolumns.name
 FROM  syscolumns
 JOIN  systypes on syscolumns.xusertype = systypes.xusertype
 WHERE  systypes.name not like 'timestamp' and id = object_id(@tablename)
 declare @colname varchar(100)
 declare @colnames varchar(8000)
 declare @first tinyint
 SET @colnames = ''
 SET @first = 1
 while (1>0)
 begin
  SELECT  @colname = colname
  FROM @cols
  WHERE colid = (SELECT min(colid)
    FROM @cols)
  if @@rowcount = 0
  begin
   break
  end
  else
  begin
   if @first = 1
   begin
    SET @first = 0
   end
   else
   begin
    SET @colnames = @colnames + ','
   end
  end
  SET @colnames = @colnames + '[' + @colname+']'
  DELETE
  FROM @cols
  WHERE colname = @colname
 end
 declare @addcols varchar(1000)
 SET @addcols = ',[sz30auditusername],[sz1auditType],[sz30audithostname],[dtaudittimestamp]'
 select @id = deltrig from sysobjects where name = @tablename and type = 'U'
 if @id = 0
 begin
  print '--Warning this table has no delete trigger - Printing please run'
  SELECT @statement = 'Create trigger tr' + @tablename + 'Delete on ' + @tablename + ' for delete as if exists(select sz30tablename from auditlist where sz30tablename=''' + @tablename + ''') insert into ' + @tablename + '_a (' + @colnames+ @addcols + ') select ' + @colnames +',user_name(),''D'',host_name(),getdate() from deleted'
  print @statement
  print 'go'
 end
 else
 begin
  if not exists(select * from sysdepends where depid = object_id('auditlist') and id = @id)
   print '--Warning this table''s delete trigger does not access audit log'
  if not exists(select * from sysdepends where depid = object_id(@audittable) and id = @id)
   print '--Warning this table''s delete trigger does not insert into audit log'
  SELECT @statement = 'Create trigger tr' + @tablename + 'Delete on ' + @tablename + ' for delete as if exists(select sz30tablename from auditlist where sz30tablename=''' + @tablename + ''') insert into ' + @tablename + '_a (' + @colnames+ @addcols + ') select ' + @colnames +',user_name(),''D'',host_name(),getdate() from deleted'
  print @statement
  print 'go'
 end
 select @id = Updtrig from sysobjects where name = @tablename and type = 'U'
 if @id = 0
 begin
  print '--Warning this table has no update trigger - Printing please run'
  SELECT @statement = 'Create trigger tr' + @tablename + 'Update on ' + @tablename + ' for update as if exists(select sz30tablename from auditlist where sz30tablename=''' + @tablename + ''') insert into ' + @tablename + '_a (' + @colnames+ @addcols + ') select ' + @colnames +',user_name(),''U'',host_name(),getdate() from inserted'
  print @statement
  print 'go'
 end
 else
 begin
  if not exists(select * from sysdepends where depid = object_id('auditlist') and id = @id)
   print '--Warning this table''s update trigger does access audit log'
  if not exists(select * from sysdepends where depid = object_id(@audittable) and id = @id)
   print '--Warning this table''s update trigger does not insert into audit log'
  SELECT @statement = 'Create trigger tr' + @tablename + 'Update on ' + @tablename + ' for update as if exists(select sz30tablename from auditlist where sz30tablename=''' + @tablename + ''') insert into ' + @tablename + '_a (' + @colnames+ @addcols + ') select ' + @colnames +',user_name(),''U'',host_name(),getdate() from inserted'
  print @statement
  print 'go'
 end
 select @id = Instrig from sysobjects where name = @tablename and type = 'U'
 if @id = 0
 begin
  print '--Warning this table has no insert trigger - Printing please run'
  SELECT @statement = 'Create trigger tr' + @tablename + 'Insert on ' + @tablename + ' for insert as if exists(select sz30tablename from auditlist where sz30tablename=''' + @tablename + ''') insert into ' + @tablename + '_a (' + @colnames+ @addcols + ') select ' + @colnames +',user_name(),''I'',host_name(),getdate() from inserted'
  print @statement
  print 'go'
 end
 else
 begin
  if not exists(select * from sysdepends where depid = object_id('auditlist') and id = @id)
   print '--Warning this table''s insert trigger does access audit log'
  if not exists(select * from sysdepends where depid = object_id(@audittable) and id = @id)
   print '--Warning this table''s insert trigger does not insert into audit log'
  SELECT @statement = 'Create trigger tr' + @tablename + 'Insert on ' + @tablename + ' for insert as if exists(select sz30tablename from auditlist where sz30tablename=''' + @tablename + ''') insert into ' + @tablename + '_a (' + @colnames+ @addcols + ') select ' + @colnames +',user_name(),''I'',host_name(),getdate() from inserted'
  print @statement
  print 'go'
 end
 if @status = 0
 begin
  exec sp_dboption @databasename, 'select into/bulkcopy',FALSE
 end

GO


then run proc

exec sp_addaudittable 'tablename'

This will create a table tablename_a

it will then print the code to create the triggers, copy this out and run it into the database you now have the triggers for audit.


SET
GO
SET
GO
SET
GO
CREATE