/* 

AutoAudit script
Paul Nielsen
www.sqlserverbible.com


----------------------------------
version 1.00 - Jan 15, 2007

This script creates the audit table and builds 4 stored procedures. 

AutoAudit 'schema', 'table'
which: 
   1) creates dbo.audit  table if not already there
   2) adds created and modified columns to table
   3) builds insert, update, and modified audit trail trigger

AutoAditDrop 'schema', 'table'
which: 
1)	drops insert, update, and modified audit trail trigger

AutoAuditAll  
AuditDropAll
1)	runs the autoaudit or autoauditdrop for every table in the database other than the audit table. 

This is only a version 1, so test before you put it in production. 
Im open to suggestions and requests. 

This version is limited to tables with single column primary keys. 
But thats easy to change if enough readers ask for it. Also, in the next version Im going to add error handling. 

-----------------------------------
version 1.01 - Jan 15, 2007
   added row version column, incremented by the modified trigger
   cleaned up how the tablename is written to the audit.tablename column 
   added delete trigger, which just writes the table, pk, and operation ('d') to the audit table
   changed Audit.[Column] to Audit.ColumnName

		-- Query to determine lastvalues of deleted rows 
		Select TableName, PrimaryKey, ColumnName, NewValue as LastValue from dbo.audit 
		 Where Operation IN ('i', 'u') 
			AND AuditID IN (
				Select Max(AuditID) 
				  FROM dbo.audit a
					JOIN (SELECT TableName, PrimaryKey FROM dbo.audit where operation = 'd') d
					  on a.tablename = d.tablename and a.primarykey = d.primarykey
				  GROUP BY a.TableName, a.PrimaryKey, a.ColumnName )

-----------------------------------
version 1.02 - Jan 16, 2007
   fixed bug: Duplicate Columns. databases with user-defined types was causing the user-defined types to show up as system types. 
   added code gen to create [table]_deleted view that returns all deleted rows for the table

-----------------------------------
version 1.03 - Jan 16, 2007
   converted from cursor to Multiple Assignment Variable for building of for-each-column code
   added created, modifed, and delted columns to _deleted view 

-----------------------------------
version 1.04 - Jan 18, 2007
  minor clean-up on _deleted view. Removed extra Primary Key Column. 

-----------------------------------
version 1.05 - Jan 18, 2007
  changed from writing just the delete bit to writing the whole row. 
  modified _deleted view to return RowVersion

-----------------------------------
version 1.06 - Jan 30, 2007
  added host_name to audit trail
  improved modifed trigger run-away recursive trigger detection
  added basic error-trapping

-----------------------------------
version 1.07 - Feb 6, 2007
  idea from Gary Lail - don't log inserts, only updates
  added pRollbackAudit procedure
  changed all stored procedure names to pName


CREATE PROC usp AS SELECT OBJECT_NAME( @@PROCID )

-----------------------------------
version 1.08 - June 25, 2008
  case sensitive cleanup
  defaults named propoerly
  defaults and columns dropped in AutoAuditDrop proc


*/

-- USE AdventureWorks  -- change to your database



IF Object_id('pAutoAudit') IS NOT NULL
  DROP PROC pAutoAudit
IF Object_id('pAutoAuditAll') IS NOT NULL
  DROP PROC pAutoAuditAll
IF Object_id('pAutoAuditDrop') IS NOT NULL
  DROP PROC pAutoAuditDrop
IF Object_id('pAutoAuditDropAll') IS NOT NULL
  DROP PROC pAutoAuditDropAll

go
IF Object_id('Audit') IS NULL
	CREATE TABLE dbo.Audit (
	  AuditID BIGINT NOT NULL IDENTITY PRIMARY KEY CLUSTERED,
	  AuditDate DATETIME NOT NULL,
	  HostName sysname NOT NULL,
	  SysUser VARCHAR(50) NOT NULL,
	  Application VARCHAR(50) NOT NULL,
	  TableName sysname NOT NULL,
	  Operation CHAR(1) NOT NULL, -- i,u,d
	  PrimaryKey VARCHAR(20) NOT NULL, -- edit to suite
	  RowDescription VARCHAR(50) NULL,-- Optional
	  SecondaryRow VARCHAR(50) NULL, -- Optional 
	  ColumnName sysname NULL, -- required for i,u, and now D (ver 1.07), should add check constraint
	  OldValue VARCHAR(50) NULL, -- edit to suite (Nvarchar() ?, varchar(MAX) ? ) 
	  NewValue VARCHAR(50) NULL -- edit to suite (Nvarchar() ?, varchar(MAX) ? )
	  )  -- optimzed for inserts, no non-clustered indexes

go --------------------------------------------------------------------

CREATE PROC pAutoAudit (
   @SchemaName VARCHAR(50),
   @TableName VARCHAR(50)
) 
AS 
SET NoCount ON

-- script to create autoAudit triggers
DECLARE 
   @SQL NVARCHAR(max),
   @ColumnName  sysname,
   @PKColumnName sysname

-- drop existing insert trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Audit_Insert' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Insert'
EXEC (@SQL)

-- drop existing update trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Audit_Update' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Update'
EXEC (@SQL)

-- drop existing modified trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Modified' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Modified'
EXEC (@SQL)

-- drop existing delete trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Audit_Delete' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Delete'
EXEC (@SQL)

-- drop existing delete view
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''v' + @TableName + '_Deleted' + ''' )'
       + ' DROP VIEW ' + @SchemaName + '.v' + @TableName + '_Deleted'
EXEC (@SQL)



-- add created column 
IF not exists (select *
			  from sys.tables t
				join sys.schemas s
				  on s.schema_id = t.schema_id
				join sys.columns c
				  on t.object_id = c.object_id
			  where  t.name = @TableName AND s.name = @SchemaName and c.name = 'Created')
  BEGIN
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' ADD Created DateTime NOT NULL constraint ' + @TableName + '_Created_df Default GetDate()'
    EXEC (@SQL)
  END


-- add modified column 
IF not exists( select *
			  from sys.tables t
				join sys.schemas s
				  on s.schema_id = t.schema_id
				join sys.columns c
				  on t.object_id = c.object_id
			  where  t.name = @TableName AND s.name = @SchemaName and c.name = 'Modified')
  BEGIN   
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' ADD Modified DateTime NOT NULL constraint ' + @TableName + '_Modified_df Default GetDate()'
    EXEC (@SQL)
  END

-- add RowVersion column 
IF not exists( select *
			  from sys.tables t
				join sys.schemas s
				  on s.schema_id = t.schema_id
				join sys.columns c
				  on t.object_id = c.object_id
			  where  t.name = @TableName AND s.name = @SchemaName and c.name = 'RowVersion')
  BEGIN   
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' ADD RowVersion INT NOT NULL constraint ' + @TableName + '_RowVersion_df Default 1'
    EXEC (@SQL)
  END


-- get PK Column (1)  
select @PKColumnName = c.name
  from sys.tables t
    join sys.schemas s
      on s.schema_id = t.schema_id
    join sys.indexes i
      on t.object_id = i.object_id
    join sys.index_columns ic
  	  on i.object_id = ic.object_id
      and i.index_id = ic.index_id
    join sys.columns c
      on ic.object_id = c.object_id
      and ic.column_id = c.column_id
  where is_primary_key = 1 AND t.name = @TableName AND s.name = @SchemaName AND ic.index_column_id = 1

-- build modified trigger 
SET @SQL = 'CREATE TRIGGER ' + @SchemaName + '.' + @TableName + '_Modified' + ' ON '+ @SchemaName + '.' + @TableName + Char(13) + Char(10)
       + ' AFTER Update' + Char(13) + Char(10) + ' NOT FOR REPLICATION AS' + Char(13) + Char(10)
       + ' SET NoCount On ' + Char(13) + Char(10)
       + ' -- generated by AutoAudit on ' + Convert(VARCHAR(30), GetDate(),100)  + Char(13) + Char(10)
       + ' -- created by Paul Nielsen ' + Char(13) + Char(10)
       + ' -- www.SQLServerBible.com ' + Char(13) + Char(10) + Char(13) + Char(10)

       + ' Begin Try ' + Char(13) + Char(10)
       + ' If Trigger_NestLevel(object_ID(N''[' + @SchemaName + '].[' + @TableName + '_Modified]'')) > 1 Return;' + Char(13) + Char(10)

       + ' If (Update(Created) or Update(Modified)) AND Trigger_NestLevel() = 1' + Char(13) + Char(10)
       + ' Begin; Raiserror(''Update failed.'', 16, 1); Rollback;  Return; End;' + Char(13) + Char(10)

       + ' -- Update the Modified date' + Char(13) + Char(10)
       + ' UPDATE [' + @SchemaName + '].[' + @TableName + ']'+ Char(13) + Char(10)
       + ' SET Modified = getdate(), ' + Char(13) + Char(10)
       + '        [RowVersion] = [' + @TableName + '].[RowVersion] + 1 ' + Char(13) + Char(10)
       + '   FROM [' + @SchemaName + '].[' + @TableName + ']' + Char(13) + Char(10)
       + '     JOIN Inserted'  + Char(13) + Char(10)
       + '       ON [' + @TableName + '].[' + @PKColumnName + '] = Inserted.[' + @PKColumnName + ']'
       + ' End Try ' + Char(13) + Char(10)
       + ' Begin Catch ' + Char(13) + Char(10)
       + '   Raiserror(''error in [' + + @SchemaName + '].[' + @TableName +'_modified] trigger'', 16, 1 ) with log' + Char(13) + Char(10)
       + ' End Catch ' 

    EXEC (@SQL)

--------------------------------------------------------------------------------------------
-- build insert trigger 
SET @SQL = 'CREATE TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Insert' + ' ON '+ @SchemaName + '.' + @TableName + Char(13) + Char(10)
       + ' AFTER Insert' + Char(13) + Char(10) + ' NOT FOR REPLICATION AS' + Char(13) + Char(10)
       + ' SET NoCount On ' + Char(13) + Char(10)
       + ' -- generated by AutoAudit on ' + Convert(VARCHAR(30), GetDate(),100)  + Char(13) + Char(10)
       + ' -- created by Paul Nielsen ' + Char(13) + Char(10)
       + ' -- www.SQLServerBible.com ' + Char(13) + Char(10) + Char(13) + Char(10)
       + 'DECLARE @AuditTime DATETIME' + Char(13) + Char(10)
       + 'SET @AuditTime = GetDate()' + Char(13) + Char(10) + Char(13) + Char(10)
       + ' Begin Try ' + Char(13) + Char(10)

-- for PK column
	select @SQL = @SQL + 
		     '   INSERT dbo.Audit (AuditDate, SysUser, Application, HostName, TableName, Operation, PrimaryKey, RowDescription, SecondaryRow, ColumnName, NewValue)' + Char(13) + Char(10)
          + '   SELECT  @AuditTime, suser_sname(), APP_NAME(), Host_Name(), ' 
          + '''' + @SchemaName + '.' + @TableName + ''', ''i'','   
          + ' Inserted.[' + @PKColumnName + '],' + Char(13) + Char(10) 
          + '        NULL,     -- Row Description (e.g. Order Number)' + Char(13) + Char(10)   
          + '        NULL,     -- Secondary Row Value (e.g. Order Number for an Order Detail Line)' + Char(13) + Char(10)
          + '        ''[' + c.name + ']'','   
          + ' Cast(Inserted.[' + c.name + '] as VARCHAR(50))' + Char(13) + Char(10)
          + '          FROM Inserted' + Char(13) + Char(10)
          + '          WHERE Inserted.['+ c.name + '] is not null' + Char(13) + Char(10)+ Char(13) + Char(10)
	  from sys.tables as t
		join sys.columns as c
		  on t.object_id = c.object_id
		join sys.schemas as s
		  on s.schema_id = t.schema_id
		join sys.types as ty
		  on ty.user_type_id = c.user_type_id
		join sys.types st
		  on ty.system_type_id = st.user_type_id
      where t.name = @TableName AND s.name = @SchemaName 
         AND c.name = @PKColumnName
         AND c.is_computed = 0
        AND st.name IN ('tinyint', 'smallint', 'int', 'money', 'smallmoney', 'decimal', 'bigint', 'datetime', 'smalldateteime', 'numeric',  'varchar', 'nvarchar', 'char', 'nchar', 'bit')
	  order by c.column_id

	select @SQL = @SQL + 
       + ' End Try ' + Char(13) + Char(10)
       + ' Begin Catch ' + Char(13) + Char(10)
       + '   Raiserror(''error in [' + + @SchemaName + '].[' + @TableName +'_audit_insert] trigger'', 16, 1 ) with log' + Char(13) + Char(10)
       + ' End Catch ' 


EXEC (@SQL) -- commented out with Version 1.07

--------------------------------------------------------------------------------------------
-- build update trigger 

SET @SQL = 'CREATE TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Update' + ' ON '+ @SchemaName + '.' + @TableName + Char(13) + Char(10)
       + ' AFTER Update' + Char(13) + Char(10) + ' NOT FOR REPLICATION AS' + Char(13) + Char(10)
       + ' SET NoCount On ' + Char(13) + Char(10)
       + ' -- generated by AutoAudit on ' + Convert(VARCHAR(30), GetDate(),100)  + Char(13) + Char(10)
       + ' -- created by Paul Nielsen ' + Char(13) + Char(10)
       + ' -- www.SQLServerBible.com ' + Char(13) + Char(10) + Char(13) + Char(10)
       + 'DECLARE @AuditTime DATETIME' + Char(13) + Char(10)
       + 'SET @AuditTime = GetDate()' + Char(13) + Char(10) + Char(13) + Char(10)
       + ' Begin Try ' + Char(13) + Char(10)
-- for each column
	select @SQL = @SQL + 
	   +  ' IF UPDATE([' + c.name + '])' + Char(13) + Char(10)
       + '   INSERT dbo.Audit (AuditDate, SysUser, Application, HostName, TableName, Operation, PrimaryKey, RowDescription, SecondaryRow, ColumnName, OldValue, NewValue)' + Char(13) + Char(10)
       + '   SELECT  @AuditTime, suser_sname(), APP_NAME(), Host_Name(), ' 
       + '''' + @SchemaName + '.' + @TableName + ''', ''u'','   
       + ' Inserted.[' + @PKColumnName + '],' + Char(13) + Char(10) 
       + '        NULL,     -- Row Description (e.g. Order Number)' + Char(13) + Char(10)   
       + '        NULL,     -- Secondary Row Value (e.g. Oder Number for an Order Detail Line)' + Char(13) + Char(10)
       + '        ''[' + c.name+ ']'','   
       + ' Cast(Deleted.[' + c.name + '] as VARCHAR(50)), ' 
       + ' Cast(Inserted.[' + c.name + '] as VARCHAR(50))' + Char(13) + Char(10)
       + '          FROM Inserted' + Char(13) + Char(10)
       + '             JOIN Deleted' + Char(13) + Char(10)
       + '               ON Inserted.[' + @PKColumnName + '] = Deleted.[' + @PKColumnName + ']' + Char(13) + Char(10)
       + '               AND isnull(Inserted.[' + c.name + '],'''') <> isnull(Deleted.[' + c.name + '],'''')' + Char(13) + Char(10)+ Char(13) + Char(10)
	  from sys.tables as t
		join sys.columns as c
		  on t.object_id = c.object_id
		join sys.schemas as s
		  on s.schema_id = t.schema_id
		join sys.types as ty
		  on ty.user_type_id = c.user_type_id
		join sys.types st
		  on ty.system_type_id = st.user_type_id
      where t.name = @TableName AND s.name = @SchemaName 
         AND c.name NOT IN ('created', 'modified','RowVersion')
         AND c.is_computed = 0
        AND st.name IN ('tinyint', 'smallint', 'int', 'money', 'smallmoney', 'decimal', 'bigint', 'datetime', 'smalldateteime', 'numeric',  'varchar', 'nvarchar', 'char', 'nchar', 'bit')
	  order by c.column_id

	select @SQL = @SQL + 
       + ' End Try ' + Char(13) + Char(10)
       + ' Begin Catch ' + Char(13) + Char(10)
       + '   Raiserror(''error in [' + + @SchemaName + '].[' + @TableName +'_audit_update] trigger'', 16, 1 ) with log' + Char(13) + Char(10)
       + ' End Catch ' 


EXEC (@SQL)


--------------------------
-- build delete trigger 
SET @SQL = 'CREATE TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Delete' + ' ON '+ @SchemaName + '.' + @TableName + Char(13) + Char(10)
       + ' AFTER Delete' + Char(13) + Char(10) + ' NOT FOR REPLICATION AS' + Char(13) + Char(10)
       + ' SET NoCount On ' + Char(13) + Char(10)
       + ' -- generated by AutoAudit on ' + Convert(VARCHAR(30), GetDate(),100)  + Char(13) + Char(10)
       + ' -- created by Paul Nielsen ' + Char(13) + Char(10)
       + ' -- www.SQLServerBible.com ' + Char(13) + Char(10) + Char(13) + Char(10)
       + 'DECLARE @AuditTime DATETIME' + Char(13) + Char(10)
       + 'SET @AuditTime = GetDate()' + Char(13) + Char(10) + Char(13) + Char(10)
       + ' Begin Try ' + Char(13) + Char(10)

-- for each column
	select @SQL = @SQL + 
		     '   INSERT dbo.Audit (AuditDate, SysUser, Application, HostName, TableName, Operation, PrimaryKey, RowDescription, SecondaryRow, ColumnName, OldValue)' + Char(13) + Char(10)
          + '   SELECT  @AuditTime, suser_sname(), APP_NAME(), Host_Name(),' 
          + '''' + @SchemaName + '.' + @TableName + ''', ''d'','   
          + ' deleted.[' + @PKColumnName + '],' + Char(13) + Char(10) 
          + '        NULL,     -- Row Description (e.g. Order Number)' + Char(13) + Char(10)   
          + '        NULL,     -- Secondary Row Value (e.g. Oder Number for an Order Detail Line)' + Char(13) + Char(10)
          + '        ''[' + c.name + ']'','   
          + ' Cast(deleted.[' + c.name + '] as VARCHAR(50))' + Char(13) + Char(10)
          + '          FROM deleted' + Char(13) + Char(10)
          + '          WHERE deleted.['+ c.name + '] is not null' + Char(13) + Char(10)+ Char(13) + Char(10)
	  from sys.tables as t
		join sys.columns as c
		  on t.object_id = c.object_id
		join sys.schemas as s
		  on s.schema_id = t.schema_id
		join sys.types as ty
		  on ty.user_type_id = c.user_type_id
		join sys.types st
		  on ty.system_type_id = st.user_type_id
      where t.name = @TableName AND s.name = @SchemaName 
         -- AND c.name NOT IN ('created', 'modified','RowVersion')
         AND c.is_computed = 0
        AND st.name IN ('tinyint', 'smallint', 'int', 'money', 'smallmoney', 'decimal', 'bigint', 'datetime', 'smalldateteime', 'numeric',  'varchar', 'nvarchar', 'char', 'nchar', 'bit')
	  order by c.column_id

	select @SQL = @SQL + 
       + ' End Try ' + Char(13) + Char(10)
       + ' Begin Catch ' + Char(13) + Char(10)
       + '   Raiserror(''error in [' + + @SchemaName + '].[' + @TableName +'_audit_delete trigger'', 16, 1 ) with log' + Char(13) + Char(10)
       + ' End Catch ' 

EXEC (@SQL)


--------------------------------------------------------------------------------------------
-- build _Deleted view

/* Sample: 
CREATE VIEW Production.vCulture_Deleted
as
	SELECT 
		Max(Case ColumnName WHEN '[CultureID]' THEN OldValue ELSE '' END) AS [CultureID],
		Max(Case ColumnName WHEN '[Name]' THEN OldValue ELSE '' END) AS [Name],
		Max(Case ColumnName WHEN '[Created]' THEN OldValue ELSE '' END) AS [Created],
		Max(Case ColumnName WHEN '[Modified]' THEN OldValue ELSE '' END) AS Modified,
		Max(Case ColumnName WHEN '[Rowversion]' THEN OldValue ELSE '' END) AS [Rowversion],
        MAX(AuditDate) AS 'Deleted'
	FROM Audit 
	Where TableName = 'Production.Culture' AND Operation = 'd'
	GROUP BY PrimaryKey 
*/

SET @SQL = 'CREATE VIEW ' + @SchemaName + '.v' + @TableName + '_Deleted' + Char(13) + Char(10)
       + 'AS ' + Char(13) + Char(10) 
       + ' -- generated by AutoAudit on ' + Convert(VARCHAR(30), GetDate(),100)  + Char(13) + Char(10)
       + ' -- created by Paul Nielsen ' + Char(13) + Char(10)
       + ' -- www.SQLServerBible.com ' + Char(13) + Char(10) + Char(13) + Char(10)
       + 'SELECT ' + Char(13) + Char(10)

-- for each column
SELECT @SQL = @SQL +
		  '     Max(Case ColumnName WHEN ''[' + c.name + ']'' THEN OldValue ELSE '''' END) AS [' + c.name +'],'  + Char(13) + Char(10)
	  from sys.tables as t
		join sys.columns as c
		  on t.object_id = c.object_id
		join sys.schemas as s
		  on s.schema_id = t.schema_id
		join sys.types as ty
		  on ty.user_type_id = c.user_type_id
		join sys.types st
		  on ty.system_type_id = st.user_type_id
      where t.name = @TableName AND s.name = @SchemaName 
         AND c.is_computed = 0
        AND st.name IN ('tinyint', 'smallint', 'int', 'money', 'smallmoney', 'decimal', 'bigint', 'datetime', 'smalldateteime', 'numeric',  'varchar', 'nvarchar', 'char', 'nchar', 'bit')
	  order by c.column_id

SET @SQL = @SQL
        + '      MAX(AuditDate) AS ''Deleted'''  + Char(13) + Char(10)
	    + '  FROM Audit'   + Char(13) + Char(10)
	    + '  Where TableName = ''' +@SchemaName + '.' + @TableName + ''' AND Operation = ''d'''  + Char(13) + Char(10)
	    + '  GROUP BY PrimaryKey' 

EXEC (@SQL)

RETURN -- END OF SPROC

go --------------------------------------------------------------------
CREATE PROC pAutoAuditDrop (
   @SchemaName VARCHAR(50),
   @TableName VARCHAR(50)
) 
AS 
SET NoCount ON

DECLARE 
   @SQL NVARCHAR(max)

-- drop default constraints

If Exists (select * from sys.objects where name = 'Created_df')
  BEGIN 
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' drop constraint ' + @TableName + '_Created_df'
    EXEC (@SQL)
  END

If Exists (select * from sys.objects where name = 'Modified_df')
  BEGIN 
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' drop constraint ' + @TableName + '_Modified_df'
    EXEC (@SQL)
  END

If Exists (select * from sys.objects where name = 'RowVersion_df')
  BEGIN 
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' drop constraint ' + @TableName + '_RowVersion_df'
    EXEC (@SQL)
  END

-- drop created column 
IF exists (select *
			  from sys.tables t
				join sys.schemas s
				  on s.schema_id = t.schema_id
				join sys.columns c
				  on t.object_id = c.object_id
			  where  t.name = @TableName AND s.name = @SchemaName and c.name = 'Created')
  BEGIN
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' DROP COLUMN Created'
    EXEC (@SQL)
  END

-- add modified column 
IF exists( select *
			  from sys.tables t
				join sys.schemas s
				  on s.schema_id = t.schema_id
				join sys.columns c
				  on t.object_id = c.object_id
			  where  t.name = @TableName AND s.name = @SchemaName and c.name = 'Modified')
  BEGIN   
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' DROP COLUMN Modified'
    EXEC (@SQL)
  END

-- add RowVersion column 
IF exists( select *
			  from sys.tables t
				join sys.schemas s
				  on s.schema_id = t.schema_id
				join sys.columns c
				  on t.object_id = c.object_id
			  where  t.name = @TableName AND s.name = @SchemaName and c.name = 'RowVersion')
  BEGIN   
    SET @SQL = 'ALTER TABLE ' + @SchemaName + '.' + @TableName + ' DROP COLUMN RowVersion'
    EXEC (@SQL)
  END

-- drop existing insert trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Audit_Insert' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Insert'
EXEC (@SQL)

-- drop existing update trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Audit_Update' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Update'
EXEC (@SQL)

-- drop existing modified trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Modified' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Modified'
EXEC (@SQL)

-- drop existing delete trigger
SET @SQL = 'If EXISTS (Select * from sys.objects where name = '
       + '''' + @TableName + '_Audit_Delete' + ''' )'
       + ' DROP TRIGGER ' + @SchemaName + '.' + @TableName + '_Audit_Delete'
EXEC (@SQL)

go -----------------------------------------------------------------------
CREATE PROC pAutoAuditAll 
AS 
SET NoCount ON 
DECLARE 
   @TableName VARCHAR(50), 
   @SchemaName VARCHAR(50), 
   @SQL NVARCHAR(max)
-- for each table
-- 1
DECLARE cTables CURSOR FAST_FORWARD READ_ONLY
  FOR  SELECT s.name, t.name 
			  from sys.tables t
				join sys.schemas s
				  on t.schema_id = s.schema_id
			 where t.name <> 'audit'
--2 
OPEN cTables
--3 
FETCH cTables INTO @SchemaName, @TableName   -- prime the cursor
WHILE @@Fetch_Status = 0 
  BEGIN
		SET @SQL = 'EXEC pAutoAudit ''' + @SchemaName + ''', ''' + @TableName + ''''
		EXEC (@SQL)
      FETCH cTables INTO @SchemaName, @TableName   -- fetch next
  END
-- 4  
CLOSE cTables
-- 5
DEALLOCATE cTables

go -----------------------------------------------------------------------
CREATE PROC pAutoAuditDropAll 
AS 
SET NoCount ON 
DECLARE 
   @TableName VARCHAR(50), 
   @SchemaName VARCHAR(50), 
   @SQL NVARCHAR(max)
-- for each table
-- 1
DECLARE cTables CURSOR FAST_FORWARD READ_ONLY
  FOR  SELECT s.name, t.name 
			  from sys.tables t
				join sys.schemas s
				  on t.schema_id = s.schema_id
			 where t.name <> 'audit'
--2 
OPEN cTables
--3 
FETCH cTables INTO @SchemaName, @TableName   -- prime the cursor
WHILE @@Fetch_Status = 0 
  BEGIN
		SET @SQL = 'EXEC pAutoAuditDrop ''' + @SchemaName + ''', ''' + @TableName + ''''
		EXEC (@SQL)
      FETCH cTables INTO @SchemaName, @TableName   -- fetch next
  END
-- 4  
CLOSE cTables
-- 5
DEALLOCATE cTables






