Trigger- dump 'inserted' table to temp table

I want to pass the 'inserted' table from a trigger into an SP, I think I need to do this by dumping inserted table into a temporary table and passing the temp table. However, I need to do this for many tables, and don't want to list all the column names for each table/trigger (maintenance nightmare).

Can I dump the 'inserted' table to a temp table WITHOUT specifying the column names?

[432 byte] By [steal] at [2007-12-28]
# 1
You could do below:

select * into #i from inserted

select * into #d from deleted

But what are you trying to do in your SP with this temporary table? Can you explain what you are trying to achieve by calling one SP from multiple triggers? You still have to know the columns that you want to operate upon in your SP and it will change depending on which trigger created the table. Additionally, this type of approach has performance implications due to constant recompilations (trigger, SP etc due to use of temporary table) and blocking issues. Typically, you want to keep the operations you perform in your trigger compact, set-based and short unit of work. Since the trigger is always in an implicit transaction you need to be even more careful as to what other resources you access or how long you perform your operations.
# 2

I need to write changes to a single audit table, with all field names and values concatenated into a single comment field. For example:

UserId=1225,LastName=Evans,FirstName=Stephanie,MiddleInitial=...

Ugly, I know but that's what they want. I have written code to dynamically get the column names for the table, create the above string with the values, but then I discovered that from within the trigger I cannot access the 'inserted' table with dynamic sql.

Any input is appreciated, a better way? I have already spent the better part of 2 days getting the below code written and now it looks like it won't work! I really do not want to literally list all of the column names to build the string for all of the triggers for all of the tables, it will never be maintained as tables evolve.

If it helps... here is my original trigger code that doesn't work because of the reference to 'inserted' within dynamic sql statement (get -Invalid Object Name 'inserted'- error)

CREATE TRIGGER [tgUsersNew] ON [dbo].[tblUsers]
FOR INSERT
AS

declare @sql1 nvarchar(4000)
declare @sql2 nvarchar(200)
declare @col_name nvarchar(40)
declare @strSql nvarchar (500)

--Note: Using the loathsome cursor because a table variable won't work with the 'Fetch' command below...
DECLARE c_cols CURSOR
KEYSET FOR SELECT c1.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLES t1
INNER JOIN INFORMATION_SCHEMA.COLUMNS c1 ON t1.TABLE_NAME = c1.TABLE_NAME
WHERE t1.TABLE_NAME = 'tblUsers'

set @sql1 = ''
set @sql2 = ''
OPEN c_cols

FETCH NEXT FROM c_cols INTO @col_name
WHILE (@@fetch_status <> -1) -- If Fetch did not fail....
BEGIN IF (@@fetch_status <> -2) --If Fetched row not missing....
BEGIN
set @strSql = 'select @strValue = cast(' + @col_Name + ' as nvarchar(40)) from inserted'
exec sp_executesql @strSql, N'@strValue nvarchar(200) out', @sql2 out
if (@sql2 is null) set @sql2 = ''
set @sql1 = @sql1 + '' + @col_name + '=' + @sql2 + ','
print 'sql1= ' + @sql1
END
FETCH NEXT FROM c_cols INTO @col_name
END
CLOSE c_cols
DEALLOCATE c_cols

INSERT INTO tblAuditAdmin
(
TableAltered,
[Action],
Comment
)
VALUES
(
'tblUsers',
'i',
@sql1
)

steal at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 3
It is hard to implement this type of auditing code. Unfortunately, the inserted/deleted virtual tables can only be accessed within the trigger code and only within the body of the trigger as static statements. So this means these tables are not visible even in dynamic SQL code executed from trigger body or SPs that are invoked from the trigger code.

So if you want to retain the existing auditing structure you will have to move this code into a SP and then do the same against the temporary table that you stored the inserted/deleted rows. Note that you are not accounting for multiple rows also in your code. So the auditing information will be inaccurate if the DML operations affects multiple rows. Additionally, the conversion of each value to string has it's own pros and cons. You are basically violating basic normalization rules by doing this. And if the combined column values exceed the 8000 bytes limit then it is much harder to generate a text/ntext value using string operations in SQL Server 2000.

My suggestion would be to create an audit table per base table similar in structure to the base table and then perform an insert from the trigger code. This will be magnitude of times faster and efficient. Coding can also be simplified to a great extent by generating the trigger code with the static insert statements for each table/DML operation. Additionally, this type of auditing information helps in data analysis since you can relate a row from the audit table to the base table easily by joining on the primary key columns to provide historical view of a row for example.
# 4

All good advice, but seeing as I am required to dump all to the same audit table I need to find the best way (or should I say the least bad way).

What about dumping the 'inserted' and 'deleted' tables to XML strings, passing the XML to an sp, and parsing the XML back into table variables in the sp? Does that sound like a better solution and do-able?

steal at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 5
Ok, I abandoned the XML approach since I'm using SQL 2000. I have accomplished my goal using #temp tables, and I modified my audit table design to store each field in a separate record instead of all fields in one record as a concatenated string. Let me know if anyone wants the code, I can post it when I get it cleaned up.
steal at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 6

Great! Could you email your code to yshteyman@hotmail.com?

I greatly appriciate your effort!

Yulia

YuliaS at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 7
Hi. I am also very interested!! htv@broadpark.no

Thank you!

Tilovi at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 8

I honestly have no idea if this would perform any better than a cursor, but the following could accomplish the task of compiling a dynamic list of column names without the use of a cursor. I know this doesn't answer the addressed problem, but since some of the ideas you posted were helpful to me, I thought I would share some of my own.

Declare @TableName VarChar(256);
Declare @v_ColName VarChar(256);

Set @TableName = 'Pump';
Set @v_ColName = '';

While Exists ( Select cols.Column_Name From information_schema.tables tabs inner join information_schema.columns cols on tabs.Table_Name = cols.table_name where tabs.table_name = @TableName And cols.Column_Name > @v_ColName )
Begin
Select @v_ColName = Min ( cols.Column_Name )
From information_schema.tables tabs
inner join information_schema.columns cols on tabs.Table_Name = cols.table_name
where tabs.table_name = @TableName And cols.Column_Name > @v_ColName;

Print @v_ColName;
End

-Steve

mr.wilson13 at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 9

Hi steal
Will you be posting your code soon? I would be interested in seeing how you did it.

Thanks

Preet

Preet at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 10

hi Steal ,

Me too wud like to see the code.

my id mohit_nitdgp@yahoo.co.in

Thanks in advnc.

MOHIT_NITDGP at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 11

I want it. qiu_zy2001@hotmail.com.

Thanks.

alexqiu at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...
# 12
Please, could you send me your code, I really apreciate it.

I will wait your reply.

Regards.

Julio del Aguila.

JuliodelAguila at 2007-9-4 > top of Msdn Tech,SQL Server,Transact-SQL...

SQL Server

Site Classified