Welcome back, data adventurers! In our previous post, we delved deep into SQL Functions, discovering how these powerful tools help us summarize, manipulate, and extract insights from our data. We explored everything from COUNT()
and SUM()
to UPPER()
, TRIM()
, and essential date functions like GETDATE()
and DATEDIFF()
.
Today, we’re taking another significant leap forward. We’ll explore a more advanced yet incredibly crucial concept: SQL Triggers. These aren’t just functions you call; they’re special database objects that automatically spring into action, ensuring your data remains consistent and your business rules are always followed.
Getting Started with Our eCommerce
Database
Before we dive into the fascinating world of SQL Triggers, as always, let’s ensure our database environment is perfectly aligned. Throughout this blog series, we’ve consistently used our custom-built eCommerce
database, complete with TeamMembers
, ClientAccounts
, and Transactions
tables.
If you’re already familiar with our eCommerce
database setup, fantastic! You’re ready to proceed.
If not, no worries at all! To follow along with the examples in this post and prepare your environment, please refer to our previous blogs where we detail the database and table creation:
- Mastering SQL Basics: Part 1 – Foundations, Table Design, and Essential Queries
- Mastering SQL Basics: Part 2 – Going Deep with JOINS
Setting up the database will ensure you can execute all the queries and gain hands-on experience as we move forward!
Here are the setup commands for our eCommerce
database:
-- Use the eCommerce database
USE eCommerce;
-- Create the TeamMembers table
CREATE TABLE TeamMembers (
member_id INT NOT NULL,
member_name VARCHAR(50) NOT NULL,
location_city VARCHAR(50) NOT NULL,
commission_rate DECIMAL(4,2) NOT NULL,
PRIMARY KEY (member_id)
);
-- Insert records into TeamMembers table
INSERT INTO TeamMembers VALUES
(101, 'Alice Smith', 'London', 0.12),
(102, 'Bob Johnson', 'San Jose', 0.13),
(103, 'Eve Davis', 'New York', 0.10),
(104, 'Charlie Brown', 'London', 0.11),
(105, 'Fran White', 'London', 0.26),
(106, 'Grace Hopper', 'Seattle', 0.09),
(107, 'David Lee', 'Barcelona', 0.15);
-- Create the ClientAccounts table
CREATE TABLE ClientAccounts (
client_id INT NOT NULL,
client_name VARCHAR(50) NOT NULL,
client_city VARCHAR(50) NOT NULL,
satisfaction_rating INT NOT NULL,
assigned_member_id INT NOT NULL,
PRIMARY KEY (client_id),
FOREIGN KEY (assigned_member_id) REFERENCES TeamMembers(member_id)
);
-- Insert records into ClientAccounts table
INSERT INTO ClientAccounts VALUES
(2001, 'Hoffman Corp', 'London', 100, 101),
(2002, 'Giovanni Ltd', 'Rome', 200, 103),
(2003, 'Liu Enterprises', 'San Jose', 200, 102),
(2004, 'Grass Solutions', 'Berlin', 300, 102),
(2005, 'Global Tech Solutions', 'Hyderabad', 150, 105),
(2006, 'Clemens Inc', 'London', 100, 101),
(2007, 'Pereira Services', 'Rome', 100, 104),
(2008, 'Cisneros Group', 'San Jose', 300, 107);
-- Create the Transactions table
CREATE TABLE Transactions (
transaction_id INT NOT NULL PRIMARY KEY,
amt DECIMAL(7,2) NOT NULL,
odate DATE NOT NULL,
cnum INT NOT NULL,
FOREIGN KEY (cnum) REFERENCES ClientAccounts(client_id)
);
-- Insert records into Transactions table
INSERT INTO Transactions VALUES
(3001, 18.69, '1996-03-10', 2008),
(3002, 1900.19,'1996-03-10', 2007),
(3003, 767.19, '1996-03-10', 2001),
(3005, 5160.45,'1996-03-10', 2003),
(3006, 1098.16,'1996-03-10', 2008),
(3007, 75.75, '1996-04-10', 2002),
(3008, 4723.00,'1996-05-10', 2006),
(3009, 1713.23,'1996-04-10', 2002),
(3010, 1309.95,'1996-06-10', 2004),
(3011, 9891.88,'1996-06-10', 2006);
For our trigger examples, we’ll add a new column, total_transaction_amount
, to the ClientAccounts
table. This column will automatically summarize the total transaction value for each client, a perfect use case for triggers!
-- Add a new column to ClientAccounts for trigger examples
ALTER TABLE ClientAccounts ADD total_transaction_amount DECIMAL(10,2);
-- Update existing client records with their initial total transaction amounts
UPDATE ClientAccounts
SET total_transaction_amount = (SELECT ISNULL(SUM(t.amt), 0) FROM Transactions t WHERE t.cnum = ClientAccounts.client_id);
-- Verify the update
SELECT client_id, client_name, total_transaction_amount FROM ClientAccounts;
Output:

What are SQL Triggers?
A SQL Trigger is a special type of stored procedure that executes automatically in response to a specified event on a table or view. These events are primarily Data Manipulation Language (DML) operations: INSERT
, UPDATE
, and DELETE
.
Unlike regular stored procedures that you explicitly call, triggers work behind the scenes. They act like an automated reaction system, ensuring that when specific data changes, related actions are performed immediately and consistently.
Why Are Triggers Important?
- Enforcing Complex Business Rules: Triggers can apply intricate logic that simple constraints can’t. For example, updating a client’s loyalty status when their total spending crosses a threshold.
- Auditing Data Changes: Automatically log who changed what, when, and how for sensitive data. This is crucial for compliance and security.
- Maintaining Data Consistency: Keep related data synchronized across different tables, preventing discrepancies.
- Implementing Custom Validations: Perform advanced checks on data before or after it’s modified.
Understanding the inserted
and deleted
Virtual Tables
When a trigger fires, SQL Server provides two essential virtual tables: inserted
and deleted
. These tables are temporary and exist only during the trigger’s execution, providing a snapshot of the data involved in the DML operation.
inserted
table: This table holds the new rows that were just inserted, or the new versions of rows after anUPDATE
. It’s available inINSERT
andUPDATE
triggers.deleted
table: This table contains the old rows that were just deleted, or the old versions of rows before anUPDATE
. It’s available inDELETE
andUPDATE
triggers.
By comparing or using data from these virtual tables, your trigger logic can perform precise actions based on the changes.
The AFTER INSERT
Trigger: Responding to New Transactions
Let’s create our first trigger. This one will automatically update the total_transaction_amount
in the ClientAccounts
table whenever a new record is inserted into the Transactions
table.
We will explore two common ways to write this trigger: using scalar variables and using direct joins with the virtual tables.
Method 1: Using Scalar Variables
This method declares local variables and populates them from the inserted
(or deleted
) table. This approach is straightforward for single-row operations.
-- Create a trigger to update total_transaction_amount after an insert into Transactions
-- (Method 1: Using Scalar Variables)
CREATE TRIGGER trg_UpdateClientTotalOnInsert_Scalar
ON Transactions
AFTER INSERT AS
BEGIN
SET NOCOUNT ON;
-- Declare variables to hold values from the inserted record
DECLARE @new_amt DECIMAL(7,2);
DECLARE @new_cnum INT;
-- Assign values from the 'inserted' virtual table to the variables.
-- IMPORTANT: This method works correctly only if ONE row is inserted at a time.
-- If multiple rows are inserted, these variables will only hold values from the LAST row.
SELECT @new_cnum = cnum, @new_amt = amt FROM inserted;
-- Update the ClientAccounts table by adding the new order amount
UPDATE ClientAccounts
SET total_transaction_amount = ISNULL(total_transaction_amount, 0) + @new_amt
WHERE client_id = @new_cnum;
END;
GO
Output: You can now see the trigger created as shown below.

How it works (Scalar Variable Method):
DECLARE @new_amt DECIMAL(7,2); DECLARE @new_cnum INT;
: Declares local variables to temporarily store the amount and client ID.SELECT @new_cnum = cnum, @new_amt = amt FROM inserted;
: This is the crucial part. It attempts to assign values from theinserted
table to the scalar variables. However, if multiple rows are inserted in a singleINSERT
statement, these variables will only capture the values from the last row processed in theinserted
table. This can lead to incorrect calculations for bulk inserts.- The
UPDATE
statement then uses these scalar variables to update theClientAccounts
table.
Let’s test it (Scalar Variable Method)!
First, check the current total_transaction_amount
for ‘Hoffman Corp’ (client ID 2001):
-- Purpose: Check current total_transaction_amount for Client ID 2001 (Hoffman Corp).
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2001;
Output:

Now, insert a single new transaction for client 2001:
INSERT INTO Transactions VALUES (3012, 1500.00, '2025-07-23', 2001);
You should see that total_transaction_amount
for ‘Hoffman Corp’ has increased by 1500! Let’s re-run the query to see below result.

Now, let’s see the limitation:
-- Insert multiple transactions in one go:
INSERT INTO Transactions VALUES
(3013, 100.00, '2025-07-23', 2001),
(3014, 200.00, '2025-07-23', 2001);
-- Purpose: Check total_transaction_amount after bulk insert (scalar trigger may show incorrect sum).
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2001;
-- If the scalar variable trigger was active, it would likely only add 100.00 (from 3014), not 200.00.
Output: Visible that only first transaction amount was added, not the second one. So, total amount now set to 2367.19, not added another transaction amount.

Let’s correct this by manually updating, to keep table clean and correct. run the below query to re-adjust values.
-- Update existing client records with their initial total transaction amounts
UPDATE ClientAccounts
SET total_transaction_amount = (SELECT ISNULL(SUM(t.amt), 0) FROM Transactions t WHERE t.cnum = ClientAccounts.client_id);
--verify
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2001;
Output: After executing above queries, you can see the proper value getting set.

Method 2: Joining with Virtual Tables (Recommended)
This method directly joins the target table with the inserted
(or deleted
) virtual table within the UPDATE
statement. This approach is robust and correctly handles both single-row and multi-row DML operations.
-- Drop the scalar variable trigger first
IF OBJECT_ID('trg_UpdateClientTotalOnInsert_Scalar', 'TR') IS NOT NULL
DROP TRIGGER trg_UpdateClientTotalOnInsert_Scalar;
GO
-- Purpose: Create a trigger to update total_transaction_amount after an insert (Joining Method - Recommended).
-- Create a trigger to update total_transaction_amount after an insert into Transactions
-- (Method 2: Joining with Virtual Tables - Recommended and Aggregated)
CREATE TRIGGER trg_UpdateClientTotalOnInsert_Join
ON Transactions
AFTER INSERT AS
BEGIN
SET NOCOUNT ON;
-- Update ClientAccounts by joining with the aggregated 'inserted' data.
-- We sum the 'amt' for each 'cnum' (client_id) in the 'inserted' table
-- to get the total amount for that client from the current batch of inserts.
UPDATE ca
SET ca.total_transaction_amount = ISNULL(ca.total_transaction_amount, 0) + i_agg.total_new_amt
FROM ClientAccounts ca
INNER JOIN (
-- Subquery to aggregate the amounts from the 'inserted' pseudo-table
SELECT
cnum,
SUM(amt) AS total_new_amt -- Sum all amounts for each client in the batch
FROM inserted
GROUP BY cnum -- Group by client number to get a sum per client
) AS i_agg ON ca.client_id = i_agg.cnum;
END;
GO
Output: After dropping earlier trigger and importing this one, you can see the new trigger added to the table as below.

How it works (Joining Method):
- The
UPDATE
statement directly uses aJOIN
clause with theinserted
table. - This allows the
UPDATE
to process all rows that were part of theINSERT
operation, ensuring thattotal_transaction_amount
is correctly updated for every affected client, even during bulk inserts. - Crucially, the subquery
(SELECT cnum, SUM(amt) AS total_new_amt FROM inserted GROUP BY cnum)
aggregates the total amount for each client from the batch of inserted transactions. This prevents the issue of only the last transaction’s amount being considered for a client when multiple transactions for that client are inserted simultaneously.
Let’s test it (Joining Method)!
First, ensure trg_UpdateClientTotalOnInsert_Scalar
is dropped or disabled if it exists to avoid conflicts. (Worried about how to DROP / DISABLE the Trigger? – We have it covered at the end, just before conclusion! )
-- Insert multiple transactions in one go (assuming trg_UpdateClientTotalOnInsert_Join is active):
INSERT INTO Transactions VALUES
(3015, 100.00, '2025-07-23', 2001),
(3016, 200.00, '2025-07-23', 2001);
INSERT INTO Transactions VALUES
(3017, 50.00, '2025-07-23', 2001),
(3018, 20.00, '2025-07-23', 2001);
-- Purpose: Verify total_transaction_amount for Client ID 2001 after bulk insert (join-based trigger).
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2001;
-- The total_transaction_amount for Hoffman Corp should now correctly reflect the sum of all new transactions.
Output: Now you can see the correct result.

Key Takeaway: While scalar variables might seem simpler for single-row operations, always prefer joining with inserted
and deleted
virtual tables in triggers. This ensures your triggers work correctly and efficiently for multi-row DML operations, which are common in real-world applications.
The AFTER UPDATE
Trigger: Adapting to Transaction Changes
When an existing transaction is updated, we need a trigger to ensure the total_transaction_amount
remains accurate. This trigger is slightly more complex as it needs to consider both the old and new values.
Method 1: Using Scalar Variables
-- Create a trigger for update on Transactions table (Method 1: Using Scalar Variables)
CREATE TRIGGER trg_UpdateClientTotalOnUpdate_Scalar
ON Transactions
AFTER UPDATE AS
BEGIN
SET NOCOUNT ON;
DECLARE @new_amt DECIMAL(10,2);
DECLARE @new_cnum INT;
DECLARE @old_amt DECIMAL(10,2);
DECLARE @old_cnum INT;
-- Get old values from 'deleted' table (limitation applies for multiple updated rows)
SELECT @old_cnum = cnum, @old_amt = amt FROM deleted;
-- Get new values from 'inserted' table (limitation applies for multiple updated rows)
SELECT @new_cnum = cnum, @new_amt = amt FROM inserted;
-- If the client number has changed (transaction reassigned)
IF @old_cnum <> @new_cnum
BEGIN
-- Deduct old amount from old client's total
UPDATE ClientAccounts
SET total_transaction_amount = ISNULL(total_transaction_amount, 0) - @old_amt
WHERE client_id = @old_cnum;
-- Add new amount to new client's total
UPDATE ClientAccounts
SET total_transaction_amount = ISNULL(total_transaction_amount, 0) + @new_amt
WHERE client_id = @new_cnum;
END
ELSE -- If only the amount changed for the same client
BEGIN
-- Adjust the total_transaction_amount by the difference
UPDATE ClientAccounts
SET total_transaction_amount = ISNULL(total_transaction_amount, 0) - @old_amt + @new_amt
WHERE client_id = @new_cnum; -- or @old_cnum, as they are the same here
END
END;
GO
How it works (Scalar Variable Method):
- This trigger declares variables for both old (
deleted
) and new (inserted
) values. - It attempts to retrieve these values into scalar variables. Again, this only works reliably for single-row
UPDATE
statements. - It then uses conditional logic (
IF @old_cnum <> @new_cnum
) to handle whether the client for the transaction has changed or just the amount. This logic is sound for a single row but fails for multi-row updates.
Let’s test it (Scalar Variable Method)!
(Temporarily drop any existing A
FTER UPDATE
triggers if needed.)
Assume ‘Hoffman Corp’ (2001) has a total that includes transaction 3012 (1500.00). ‘Giovanni Ltd’ (2002) also has an existing total.
- Scenario 1: Update amount for an existing transaction (same client)
First, let’s find out the existing total_transaction_amount
-- Purpose: Verify total_transaction_amount for Client ID 2001
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2001;
Output:

Now, execute below queries and find out the new result.
-- Update transaction 3012's amount for client 2001 from 1500.00 to 1800.00
UPDATE Transactions
SET amt = 1800.00
WHERE transaction_id = 3012;
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2001;
-- total_transaction_amount for Hoffman Corp should increase by 300 (1800 - 1500)
Output: Increase in total by 300 clearly visible.

- Scenario 2: Update client for an existing transaction (reassign transaction)
-- Reassign transaction 3012 (now 1800.00 for client 2001) to client 2002
UPDATE Transactions
SET cnum = 2002
WHERE transaction_id = 3012;
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id IN (2001, 2002);
-- Hoffman Corp's total should decrease by 1800.00
-- Giovanni Ltd's total should increase by 1800.00
Output:

Method 2: Joining with Virtual Tables (Recommended)
-- Purpose: Drop the scalar variable UPDATE trigger before creating the join-based one.
IF OBJECT_ID('trg_UpdateClientTotalOnUpdate_Scalar', 'TR') IS NOT NULL
DROP TRIGGER trg_UpdateClientTotalOnUpdate_Scalar;
GO
-- Create a trigger to update total_transaction_amount after an update on Transactions
-- (Method 2: Joining with Virtual Tables - Recommended)
CREATE TRIGGER trg_UpdateClientTotalOnUpdate_Join
ON Transactions
AFTER UPDATE AS
BEGIN
SET NOCOUNT ON;
-- Step 1: Deduct the old transaction amounts from the respective client totals.
-- We join ClientAccounts with the 'deleted' table (containing old values).
UPDATE ca
SET total_transaction_amount = ISNULL(ca.total_transaction_amount, 0) - d.amt
FROM ClientAccounts ca
INNER JOIN deleted d ON ca.client_id = d.cnum;
-- Step 2: Add the new transaction amounts to the respective client totals.
-- We join ClientAccounts with the 'inserted' table (containing new values).
UPDATE ca
SET total_transaction_amount = ISNULL(ca.total_transaction_amount, 0) + i.amt
FROM ClientAccounts ca
INNER JOIN inserted i ON ca.client_id = i.cnum;
END;
GO
How it works (Joining Method):
- AFTER UPDATE: This trigger activates after an
UPDATE
statement on Transactions. - It uses both
deleted
(for old values) andinserted
(for new values) in separateUPDATE
statements. - The first
UPDATE
statement subtracts theamt
from thedeleted
table (the value before the update) from the relevant client’s total. - The second
UPDATE
statement adds theamt
from theinserted
table (the value after the update) to the (possibly new) client’s total. This two-step process correctly handles both amount changes and client reassignments for any number of rows updated in a single statement. This is the correct and robust pattern forAFTER UPDATE
triggers.
Let’s test it (Joining Method)!
(First, ensure trg_UpdateClientTotalOnUpdate_Scalar
is dropped or disabled if it exists.)
As we are going to update two transaction for Clients 2001 and 2008, let’s first look into what total amount value is existing already with them. Execute the query below to find this out.
--fetch total transaction amount for client 2001, 2008
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id IN (2001, 2008);

Now, let’s execute the update and fetch the result.
-- Update multiple transactions in one go (assuming trg_UpdateClientTotalOnUpdate_Join is active):
-- Update transaction 3001 (client 2008, amt 18.69) to amt 50.00
-- Update transaction 3003 (client 2001, amt 767.19) to amt 800.00
UPDATE Transactions
SET amt = CASE transaction_id
WHEN 3001 THEN 50.00
WHEN 3003 THEN 800.00
END
WHERE transaction_id IN (3001, 3003);
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id IN (2001, 2008);
-- Both clients' totals should be correctly updated based on the new amounts.
Output:

The AFTER DELETE
Trigger: Cleaning Up After Removed Transactions
Finally, we’ll implement a trigger to accurately adjust the total_transaction_amount
when a transaction is deleted from the Transactions
table.
Method 1: Using Scalar Variables
-- Create a trigger for delete operation on Transactions table (Method 1: Using Scalar Variables)
CREATE TRIGGER trg_UpdateClientTotalOnDelete_Scalar
ON Transactions
AFTER DELETE AS
BEGIN
SET NOCOUNT ON;
DECLARE @deleted_cnum INT;
DECLARE @deleted_amt DECIMAL(10,2);
-- Get the deleted values (limitation applies for multiple deleted rows)
SELECT @deleted_cnum = cnum, @deleted_amt = amt FROM deleted;
-- Deduct the deleted order amount from the client's total_transaction_amount
UPDATE ClientAccounts
SET total_transaction_amount = ISNULL(total_transaction_amount, 0) - @deleted_amt
WHERE client_id = @deleted_cnum;
END;
GO
How it works (Scalar Variable Method):
- Similar to the
INSERT
andUPDATE
scalar variable methods, this retrieves values from thedeleted
table into variables. - It then uses these variables to perform the
UPDATE
. - Crucially, this method will only correctly process the last row if multiple rows are deleted in a single
DELETE
statement.
Let’s test it (Scalar Variable Method)!
(Temporarily drop any existing AFTER DELETE
triggers if needed.)
Assume ‘Giovanni Ltd’ (2002) has a total that includes transaction 3009 (1713.23).
--fetch total transaction amount for client 2002
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2002;
Output:

Now, delete a single transaction:
--delete transaction with id 3009
DELETE FROM Transactions
WHERE transaction_id = 3009;
Check the client’s total again:
--fetch total transaction amount for client 2002
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id = 2002;
Output: You should see that total_transaction_amount
for ‘Giovanni Ltd’ has decreased by 1713.23!

Method 2: Joining with Virtual Tables (Recommended)
-- Drop the scalar variable trigger if it was created for testing
IF OBJECT_ID('trg_UpdateClientTotalOnDelete_Scalar', 'TR') IS NOT NULL
DROP TRIGGER trg_UpdateClientTotalOnDelete_Scalar;
GO
-- Create a trigger to update total_transaction_amount after a delete from Transactions
-- (Method 2: Joining with Virtual Tables - Recommended and Aggregated)
CREATE TRIGGER trg_UpdateClientTotalOnDelete_Join
ON Transactions
AFTER DELETE AS
BEGIN
SET NOCOUNT ON;
-- Deduct the aggregated amount of the deleted transactions from the respective client totals.
-- We join ClientAccounts with the 'deleted' table (containing the removed transaction's values).
-- This method correctly handles single-row and multi-row deletes by summing the amounts.
UPDATE ca
SET ca.total_transaction_amount = ISNULL(ca.total_transaction_amount, 0) - d_agg.total_deleted_amt
FROM ClientAccounts ca
INNER JOIN (
-- Subquery to aggregate the amounts from the 'deleted' pseudo-table
SELECT
cnum,
SUM(amt) AS total_deleted_amt -- Sum all amounts for each client in the batch
FROM deleted
GROUP BY cnum -- Group by client number to get a sum per client
) AS d_agg ON ca.client_id = d_agg.cnum;
END;
GO
How it works (Joining Method):
- AFTER DELETE: This trigger activates after a
DELETE
operation on Transactions. - It directly joins
ClientAccounts
with thedeleted
table. - Crucially, it uses a subquery with
SUM(amt) GROUP BY cnum
on thedeleted
table. This ensures that if multiple transactions for the same client are deleted in a singleDELETE
statement, thetotal_transaction_amount
is correctly reduced by the sum of all those deleted amounts for that client. - This ensures that the
total_transaction_amount
is correctly adjusted for all clients whose transactions were deleted in a singleDELETE
statement.
Let’s test it (Joining Method)!
(First, ensure trg_UpdateClientTotalOnDelete_Scalar
is dropped or disabled if it exists.)
Now, as we are going to delete two transaction, for client 2002 and 2006, let’s find out their existing total amount as below.
--fetch transaction amount for 2002, 2006
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id IN (2002, 2006);
Output:

Now, delete the transactions by using below query and find out the result.
-- Delete multiple transactions in one go (assuming trg_UpdateClientTotalOnDelete_Join is active):
-- Delete transactions 3007 (client 2002, amt 75.75) and 3008 (client 2006, amt 4723.00)
DELETE FROM Transactions
WHERE transaction_id IN (3007, 3008);
--fetch transaction amount for 2002, 2006 again.
SELECT client_name, total_transaction_amount FROM ClientAccounts WHERE client_id IN (2002, 2006);
-- Both clients' totals should be correctly reduced based on the deleted amounts.
Output:

Now, as we have mentioned frequently about Dropping / Disabling the trigger, let’s see how to do that.
Dropping, Disabling, Enabling a Trigger
To manage triggers, you can either drop them (remove them permanently) or disable them (temporarily stop them from firing). Here are the instructions for both:
Dropping a Trigger
To permanently remove a trigger from your database, you use the DROP TRIGGER
statement. Once dropped, the trigger is gone and cannot be easily recovered without re-creating it.
Syntax:
DROP TRIGGER [schema_name].[trigger_name];
Example:
If you want to remove the trg_UpdateClientTotalOnInsert_Scalar
trigger we discussed, you would use:
DROP TRIGGER trg_UpdateClientTotalOnInsert_Scalar;
GO
Disabling and Enabling a Trigger
If you only want to temporarily prevent a trigger from firing without removing it, you can disable it. You can then re-enable it later when needed.
1. Disabling a Trigger
To disable a trigger, use the ALTER TABLE DISABLE TRIGGER
statement.
Syntax:
ALTER TABLE [table_name] DISABLE TRIGGER [trigger_name];
Example:
To disable the trg_UpdateClientTotalOnInsert_Join
trigger on the Transactions
table:
ALTER TABLE Transactions DISABLE TRIGGER trg_UpdateClientTotalOnInsert_Join;
GO
2. Enabling a Trigger
To enable a disabled trigger, use the ALTER TABLE ENABLE TRIGGER
statement.
Syntax:
ALTER TABLE [table_name] ENABLE TRIGGER [trigger_name];
Example:
To re-enable the trg_UpdateClientTotalOnInsert_Join
trigger on the Transactions
table:
ALTER TABLE Transactions ENABLE TRIGGER trg_UpdateClientTotalOnInsert_Join;
GO
Conclusion
SQL Triggers are an essential, advanced feature for building robust and reliable database systems. They provide a powerful way to automate responses to data modifications, ensuring that your data remains consistent, adheres to complex business rules, and supports critical auditing requirements.
We explored two primary methods for writing triggers: using scalar variables and joining with virtual tables. While the scalar variable approach might appear simpler for single-row operations, it has significant limitations when dealing with multi-row INSERT
, UPDATE
, or DELETE
statements. The recommended and most robust approach is to directly join with the inserted
and deleted
virtual tables, as this ensures your triggers work correctly and efficiently for all types of DML operations.
We hope this deep dive into SQL Triggers has empowered you with the knowledge to bring more automation and integrity to your database operations. Stay tuned for our next blog, where we’ll continue to explore another fundamental building block of database programming: Stored Procedures and Rules!
Leave a Reply
You must be logged in to post a comment.