Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Server - after insert trigger - update another column in the same table

I've got this database trigger:

CREATE TRIGGER setDescToUpper ON part_numbers  AFTER INSERT,UPDATE AS DECLARE @PnumPkid int, @PDesc nvarchar(128)  SET @PnumPkid = (SELECT pnum_pkid FROM inserted) SET @PDesc = (SELECT UPPER(part_description) FROM inserted)  UPDATE part_numbers set part_description_upper = @PDesc WHERE pnum_pkid=@PnumPkid  GO 

Is this a bad idea? That is to update a column on the same table. I want it to fire for both insert and update.

It works, I'm just afraid of a cyclical situation. The update, inside the trigger, fires the trigger, and again and again. Will that happen?

Please, don't nitpick at the upper case thing. Crazy situation.

like image 878
Lance Perry Avatar asked Mar 17 '11 15:03

Lance Perry


People also ask

Can we use UPDATE in trigger?

Triggers can be set to run as a part of any combination of INSERT, UPDATE, and DELETE statements.

Can I UPDATE same table in trigger?

You can resolve this problem with using before update trigger. You can update another column of updating the same table.

How do you execute a trigger only when a specific column is updated?

In SQL Server, you can create DML triggers that execute code only when a specific column is updated. The trigger still fires, but you can test whether or not a specific column was updated, and then run code only if that column was updated. You can do this by using the UPDATE() function inside your trigger.

Can we use two triggers on same table before after UPDATE?

Yes, you can definitely have more than one trigger for each operation, e.g. AFTER INSERT or AFTER UPDATE etc.


2 Answers

It depends on the recursion level for triggers currently set on the DB.

If you do this:

SP_CONFIGURE 'nested_triggers',0 GO RECONFIGURE GO 

Or this:

ALTER DATABASE db_name SET RECURSIVE_TRIGGERS OFF 

That trigger above won't be called again, and you would be safe (unless you get into some kind of deadlock; that could be possible but maybe I'm wrong).

Still, I do not think this is a good idea. A better option would be using an INSTEAD OF trigger. That way you would avoid executing the first (manual) update over the DB. Only the one defined inside the trigger would be executed.

An INSTEAD OF INSERT trigger would be like this:

CREATE TRIGGER setDescToUpper ON part_numbers INSTEAD OF INSERT AS BEGIN     INSERT INTO part_numbers (         colA,         colB,         part_description     ) SELECT         colA,         colB,         UPPER(part_description)     ) FROM         INSERTED END GO 

This would automagically "replace" the original INSERT statement by this one, with an explicit UPPER call applied to the part_description field.

An INSTEAD OF UPDATE trigger would be similar (and I don't advise you to create a single trigger, keep them separated).

Also, this addresses @Martin comment: it works for multirow inserts/updates (your example does not).

like image 79
rsenna Avatar answered Sep 25 '22 02:09

rsenna


Another option would be to enclose the update statement in an IF statement and call TRIGGER_NESTLEVEL() to restrict the update being run a second time.

CREATE TRIGGER Table_A_Update ON Table_A AFTER UPDATE  AS IF ((SELECT TRIGGER_NESTLEVEL()) < 2) BEGIN     UPDATE a     SET Date_Column = GETDATE()     FROM Table_A a     JOIN inserted i ON a.ID = i.ID END 

When the trigger initially runs the TRIGGER_NESTLEVEL is set to 1 so the update statement will be executed. That update statement will in turn fire that same trigger except this time the TRIGGER_NESTLEVEL is set to 2 and the update statement will not be executed.

You could also check the TRIGGER_NESTLEVEL first and if its greater than 1 then call RETURN to exit out of the trigger.

IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN; 
like image 40
Jorriss Avatar answered Sep 22 '22 02:09

Jorriss