My kindergarten SQL Server taught me that a trigger may be fired with multiple rows in the inserted and deleted pseudo tables. I mostly write my trigger code with this in mind, often resulting in some cursor based cludge. Now I'm really only able to test them firing for a single row at a time. How can I generate a multirow trigger and will SQL Server actually ever send a multirow trigger? Can I set a flag so that SQL Server will only fire single row triggers??
5 Answers
Trigger definitions should always handle multiple rows.
Taken from SQLTeam:
-- BAD Trigger code following:
CREATE TRIGGER trg_Table1
ON Table1
For UPDATE
AS
DECLARE @var1 int, @var2 varchar(50)
SELECT @var1 = Table1_ID, @var2 = Column2
FROM inserted
UPDATE Table2
SET SomeColumn = @var2
WHERE Table1_ID = @var1
The above trigger will only work for the last row in the inserted table.
This is how you should implement it:
CREATE TRIGGER trg_Table1
ON Table1
FOR UPDATE
AS
UPDATE t2
SET SomeColumn = i.SomeColumn
FROM Table2 t2
INNER JOIN inserted i
ON t2.Table1_ID = i.Table1_ID

- 295,962
- 43
- 465
- 541
-
`SET SomeColumn = t1.SomeColumn` seems to be wrong, where is the alias `t1` defined? Nevertheless +1 because now i understand why my trigger was only fired for the last inserted row. – Tim Schmelter Feb 08 '11 at 12:35
-
@Tim: sorry, it was a typo. Updated. – Mitch Wheat Feb 08 '11 at 14:11
Yes, if a statement affects more than one row, it should be handled by a single trigger call, as you might want to revert the whole transaction. It is not possible to split it to separate trigger calls logically and I don't think SQL Server provides such a flag. You can make SQL Server call your trigger with multiple rows by issuing an UPDATE or DELETE statement that affects multiple rows.

- 14,235
- 13
- 70
- 87

- 414,610
- 91
- 852
- 789
-
4I'll go a bit further and say your triggers should ALWAYS take multiple rows into account, whether or not you expect them to be called that way. – Dave Markle Jan 02 '09 at 20:44
-
Dave, absolutely. I just wanted to clarify why such a thing should not logically be possible. The trigger should have knowledge about the whole happening "at once" which won't be possible if it ran for every row. Also a DELETE MyTable statement would've taken forever if the trigger is expensive – Mehrdad Afshari Jan 02 '09 at 20:47
-
@Dave Markle: Totally agree. Would vote up your comment if I could! – Mitch Wheat Jan 03 '09 at 00:16
First it concerns me that you are making the triggers handle multiple rows by using a cursor. Do not do that! Use a set-based statment instead jioining to the inserted or deleted pseudotables. Someone put one of those cursor based triggerson our database before I came to work here. It took over forty minutes to handle a 400,00 record insert (and I often have to do inserts of over 100,000 records to this table for one client). Changing it to a set-based solution changed the time to less than a minute. While all triggers must be capable of handling multiple rows, you must not do so by creating a performance nightmare.
If you can write a select statment for the cusor, you can write an insert, update or delete based on the same select statment which is set-based.

- 94,695
- 15
- 113
- 186
-
I need to execute the same set of updates after a trigger fires, in 3 different places (triggers). For maintainability reasons I put all the updates into a SP and let the triggers just call the procedure. So I need a cursor here in case of a multi row update ... :| – IngoB Nov 29 '17 at 12:29
-
1You can write a stored proc that uses a table variable as an input variable and performs set-based work. Under no circumstances use a cursor in a trigger. – HLGEM Nov 29 '17 at 14:59
-
1Further, performance is far more critical than maintainability. Maintainability should never trump performance. – HLGEM Nov 29 '17 at 15:00
I've always written my triggers to handle multiple rows, it was my understanding that if a single query inserted/updated/deleted multiple rows then only one trigger would fire and as such you would have to use a cursor to move through the records one by one.

- 26,441
- 7
- 76
- 90
One SQL statement always invokes one trigger execution - that's part of the definition of a trigger. (It's also a circumstance that seems to at least once trip up everyone who writes a trigger.) I believe you can discover how many records are being affected by inspecting @@ROWCOUNT.

- 37,399
- 13
- 80
- 138