2026-07-15

How can I get a trigger to fire on each inserted row during an INSERT INTO Table (etc) SELECT * FROM Table2?

Stefan Bogdanescu

Stefan Bogdanescu

Founder & Senior Architect

How can I get a trigger to fire on each inserted row during an INSERT INTO Table (etc) SELECT * FROM Table2?

Mastering Triggers: Firing Events for Bulk INSERT Operations

I've been wrestling with a common SQL challenge lately: how to make an AFTER INSERT trigger execute logic for every single row inserted when that insertion is performed in bulk using a SELECT statement. It’s a scenario where the behavior of triggers can seem counter-intuitive, especially when dealing with large data migrations or nightly batch processes.

The issue arises because standard SQL Server triggers, when executed in response to a multi-row INSERT, operate on the set of rows provided by the pseudo-table (like inserted or deleted). If you execute a single bulk statement, the trigger might only process the operation as a single event, leading to incomplete or incorrect data processing.

This post will dive into why this happens and provide the robust, set-based solution for ensuring your triggers fire correctly on every inserted row, regardless of whether it’s a single insertion or a massive batch.

The Pitfall of Bulk Operations in Triggers

Let's look at the scenario you described. You have an AFTER INSERT trigger designed to send notifications based on the new data:

-- Original Trigger Logic (Example)
ALTER TRIGGER dbo.Notify
ON  dbo.Table
AFTER INSERT
AS 
BEGIN
    -- ... logic to send emails based on inserted data ...
END

When you execute a bulk insert like this:

INSERT INTO Table (ID, User, AssignDate, LastActionDate)
SELECT 
    ID
    ,User
    ,GETDATE() [AssignDate]
    ,GETDATE() [LastModifiedDate]
FROM Table2 /*snip*/;

The trigger fires once. While the inserted table does contain all the new rows, if your internal logic inside the trigger relies on iterating or selecting from that set in a way that assumes row-by-row processing (as is common when dealing with complex cross-table lookups), it can fail to iterate correctly over the entire batch. The system sees one large operation rather than N individual events.

The Set-Based Solution: Leveraging the inserted Table

The key to solving this lies in treating the trigger not as a single event handler, but as an event processor for a set of changes. You must explicitly query and process the entire set of rows present in the special inserted table within your trigger body. This ensures that no matter how many rows were inserted simultaneously, each one is individually handled by your custom logic.

Here is how you modify your trigger to handle bulk operations correctly:

ALTER TRIGGER dbo.Notify
ON  dbo.Table
AFTER INSERT
AS 
BEGIN
    -- Process every row in the 'inserted' set
    SELECT 
        i.ID,
        i.User
    FROM inserted i;

    -- Now perform your specific action for each row found
    DECLARE @EmailSender varchar(50)='Sender Profile';
    DECLARE @Identity int;
    DECLARE @User varchar(20);
    DECLARE @Subject varchar(50);

    -- Iterate or process based on the set you just selected
    SELECT 
        @Identity = i.ID,
        @User = i.User,
        @Subject = '(' + CONVERT(varchar,@Identity) + ')!'
    FROM inserted i;

    -- Execute the notification logic for all processed rows
    EXEC msdb.dbo.sp_send_dbmail 
        @profile_name=@EmailSender,
        @recipients=@User,
        @subject=@Subject,
        @body='//etc';
END

By selecting from inserted inside the trigger body, you force SQL Server to iterate over every row that was just added. This pattern is crucial for maintaining data integrity and ensuring complex business logic executes correctly across all operations, a principle that mirrors how efficient data handling is critical in modern frameworks like those promoted by https://laravelcompany.com.

Conclusion

Dealing with triggers during bulk operations requires shifting your perspective from event-based processing to set-based processing. Instead of assuming the trigger fires once for the entire batch, you must explicitly query and iterate over the inserted table within your trigger logic. This ensures that whether you are inserting one record or one thousand records at once, your notification system handles every single inserted row accurately and reliably. Always favor explicit set operations when dealing with database events to build scalable and predictable applications.

Note: Blog content is currently available in English.

Tags:

Enhance your marketing setup with your own email marketing platform.

Join the growing number of SaaS platforms using Laravel Mail to offer email marketing solutions to their customers.