October 7, 2004 at 5:33 pm
Hey there,
I have written some triggers that copy data from one database to another (a simplified version of replication for only a handful of tables).
However, since one of the databases is a production environment I am trying to write error handling into the triggers that will allow the initial insert to proceed even if the insert into the secondary table fails for whatever reason. This prevents users having any issues whatsoever in Production and the error can be logged and investigated without any HelpDesk calls being raised.
Is this even possible? I cannot seem to get it to work. Everytime the insert fails on the secondary table it rolls back the entire transaction including the initial insert. I have tried using savepoints and all sorts but nothing has worked.
Anyone have any ideas?
Cheers,
J
October 7, 2004 at 9:29 pm
Hey,
Check out if the T-SQL code below is what you are looking for or helps you get there:
create procedure dbo.usp_logError(@errcode integer, @errmsg varchar(500))
as
begin
insert into error_log(errcode, errmsg) values(@errcode, @errmsg)
end
create procedure dbo.usp_copyTables
as
begin
-- telling SQL Server to continue with transaction after error occurs
set xact_abort off
declare @db_error as integer
begin tran
insert into table1 select * from prod_table1
set @db_error = @@error
if ( @db_error <> 0 )
exec usp_logError(@db_error, 'copying data from [prod_table1] to [table1]')
insert into table2 select * from prod_table2
set @db_error = @@error
if ( @db_error <> 0 )
exec usp_logError(@db_error, 'copying data from [prod_table2] to [table2]')
commit tran
end
You would need to execute usp_copyTables inside your trigger like this:
exec usp_copyTables
Regards,
JP
October 8, 2004 at 4:03 am
Hi JP,
Thanks for your reply. However, I had in fact tried this thinking that this would work but alas it did not.
I am attaching an example of what I am doing (exact in every form bar the DB, table and fieldnames).
Ignore the else statement, all this is doing is setting a flag in a table that has a trigger associated which then runs a DTS package to send an email to me.
---
CREATE TRIGGER COPY_DATA_I ON TABLE1
FOR INSERT
AS
SET IDENTITY_INSERT TESTDB.DBO.TABLE1 ON
BEGIN TRAN T1
BEGIN
IF NOT EXISTS(SELECT 1 FROM TESTDB.DBO.TABLE1 WHERE ID = (SELECT ID FROM INSERTED)
BEGIN
INSERT INTO TESTDB.DBO.TABLE1
(ID
, Field1
, Field2)
SELECT ID
, Field1
, Field2
FROM TABLE1
WHERE ID = (SELECT ID FROM INSERTED)
END
ELSE
IF NOT EXISTS(SELECT 1 FROM TESTDB.DBO.COPY_FLAG WHERE SENDMAIL = 1)
BEGIN
UPDATE TESTDB.DBO.COPY_FLAG
SET SENDMAIL = 1
END
--END IF
--END IF
END
IF @@Error <> 0
BEGIN
ROLLBACK TRAN T1
RETURN
END
--END IF
COMMIT TRAN T1
SET IDENTITY_INSERT TESTDB.DBO.TABLE1 OFF
go
---
Cheers.
J
October 8, 2004 at 11:40 am
You wrote:
[...] I am trying to write error handling into the triggers that will allow the initial insert to proceed even if the insert into the secondary table fails for whatever reason. [...] Is this even possible?I'm afraid that it's not possible. In the context of a trigger (in the code of the trigger itself, or in a procedure called by a trigger), when SQL Server encounters an error, it will not execute the next statement (the way it normally does in a procedure); instead, it will rollback the entire transaction and abort the batch.
For an in-depth discussion about error handling in SQL, read the following article by Erland Sommarskog, SQL Server MVP:
http://www.sommarskog.se/error-handling-I.html#triggercontext
This means that you cannot handle an error in a trigger, you can only prevent it. For example, if you know that the INSERT could fail because of any constraints (unique, foreign keys or check constraints), you should check them before inserting the data.
Another thing: the way you wrote the trigger, it can only handle single-row inserts. You should always write triggers that handle multi-row operations correctly (see "triggers, multirow" topic in Books Online) (or prevent multirow operations from within the trigger itself). For example, the duplicate checking that you've done, could be written like this to handle multi-row inserts:
INSERT INTO TESTDB.DBO.TABLE1 (ID, Field1, Field2) SELECT ID, Field1, Field2 FROM inserted WHERE ID NOT IN (SELECT ID FROM TESTDB.DBO.TABLE1)
Razvan
October 10, 2004 at 2:32 pm
Thanks for your reply Razvan. I didn't think I was going to have much luck with that one.
Re the multirow inserts, the application that is running over the Prod DB only ever does single row inserts. However, I will still change the code to just select the values from INSERTED instead. Not sure why I didn't think to do this in the first place
Cheers,
J
Viewing 5 posts - 1 through 4 (of 4 total)
You must be logged in to reply to this topic. Login to reply