I need to write an Insert, Update Trigger on table A which will delete all rows from table B whose one column (say Desc) has values like the value inserted/updated in the table A's column (say Col1). How would I go around writing it so that I can handle both Update and Insert cases. How would I determine if the trigger is executed for an update or insert.
23 Answers
Triggers have special INSERTED
and DELETED
tables to track "before" and "after" data. So you can use something like IF EXISTS (SELECT * FROM DELETED)
to detect an update. You only have rows in DELETED
on update, but there are always rows in INSERTED
.
Look for "inserted" in CREATE TRIGGER.
Edit, 23 Nov 2011
After comment, this answer is only for INSERTED
and UPDATED
triggers.
Obviously, DELETE triggers can not have "always rows in INSERTED
" as I said above
-
1Look at @MikeTeeVee's answer below for a complete answer. This one is incomplete. – Lorenz Meyer Jan 10 '19 at 10:44
-
1@LorenzMeyer original question doesn't need that. I also have EXISTS (SELECT * FROM DELETED). Not sure why you think it's not complete... – gbn Jan 10 '19 at 12:00
-
What @LorenzMeyer may also be referring to is the statement "_You only have rows in DELETED on update, but there are **always** rows in INSERTED._" This is not _always_ true because there are times when the Update/Insert Trigger is Called and INSERTED is empty. In my answer I explain how this could be caused by the Predicate eliminating any data from changing. In this event, the Trigger is still called for the DML attempt, but the DELETED and INSERTED tables are empty. This is because SQL still accounts for times when you want to log each DML attempt (even when they do not alter any data). – MikeTeeVee Jan 24 '20 at 15:04
CREATE TRIGGER dbo.TableName_IUD
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
--
-- Check if this is an INSERT, UPDATE or DELETE Action.
--
DECLARE @action as char(1);
SET @action = 'I'; -- Set Action to Insert by default.
IF EXISTS(SELECT * FROM DELETED)
BEGIN
SET @action =
CASE
WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END
END
ELSE
IF NOT EXISTS(SELECT * FROM INSERTED) RETURN; -- Nothing updated or inserted.
...
END

- 9,921
- 16
- 55
- 70
-
1I like to write SELECT 1 FROM INSERTED too as I think it signalizes intent more clearly, but I would be disapointed by MSSQL programmers if this makes any difference in this context... – Lukáš Lánský Apr 30 '14 at 11:12
-
33IF EXISTS(SELECT * ...) and IF EXISTS(SELECT 1) ... have exactly the same performance. The row is not read nor fetched at all. In fact you can also use IF EXISTS(SELECT 1/0 ...) and it will still work and won't cause divide by zero error. – Endrju Oct 05 '14 at 10:15
-
2I was creating separate Triggers for insert ,update and delete .Now its great to know they can be combined ! – UJS Nov 16 '17 at 06:12
-
2If someone writes a query to INSERT and DELETE two different rows (insert new row and delete another row in the same script), is it possible the trigger that's set up in the way above will actually identify that as an UPDATE (even though the intent is not actually an update) due to there being data in the INSERTED/DELETED sql-tables? – mche Feb 20 '18 at 22:12
-
@mche - no, trigger is _fired_ for each statement separately, both trigger executions will be in the dark regarding other one's execution. – andowero Aug 30 '22 at 15:34
Many of these suggestions do not take into account if you run a delete statement that deletes nothing.
Say you try to delete where an ID equals some value that does not exist in the table.
Your trigger still gets called but there is nothing in the Deleted or Inserted tables.
Use this to be safe:
--Determine if this is an INSERT,UPDATE, or DELETE Action or a "failed delete".
DECLARE @Action as char(1);
SET @Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED)
THEN 'U' -- Set Action to Updated.
WHEN EXISTS(SELECT * FROM INSERTED)
THEN 'I' -- Set Action to Insert.
WHEN EXISTS(SELECT * FROM DELETED)
THEN 'D' -- Set Action to Deleted.
ELSE NULL -- Skip. It may have been a "failed delete".
END)
Special thanks to @KenDog and @Net_Prog for their answers.
I built this from their scripts.

- 18,543
- 7
- 76
- 70
-
6
-
8We may also have an UPDATE that affected no rows (or even an INSERT). – Razvan Socol Aug 31 '17 at 10:06
-
@AndrewWolfe ?what are you saying? The question specifically states that *"I need to write an Insert, Update Trigger on table A"*. Nothing about DELETE triggers. – ypercubeᵀᴹ Jan 29 '19 at 13:23
-
@ypercubeᵀᴹ sorry, about 80% of my triggers cover all three timings. – Andrew Wolfe Jan 29 '19 at 17:34
I'm using the following, it also correctly detect delete statements that delete nothing:
CREATE TRIGGER dbo.TR_TableName_TriggerName
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT * FROM INSERTED)
-- DELETE
PRINT 'DELETE';
ELSE
BEGIN
IF NOT EXISTS(SELECT * FROM DELETED)
-- INSERT
PRINT 'INSERT';
ELSE
-- UPDATE
PRINT 'UPDATE';
END
END;

- 1,240
- 1
- 10
- 8
-
4this one incorrectly detects statements that insert nothing or update nothing, though. – Roman Pekar Dec 21 '15 at 16:12
Declare @Type varchar(50)='';
IF EXISTS (SELECT * FROM inserted) and EXISTS (SELECT * FROM deleted)
BEGIN
SELECT @Type = 'UPDATE'
END
ELSE IF EXISTS(SELECT * FROM inserted)
BEGIN
SELECT @Type = 'INSERT'
END
ElSE IF EXISTS(SELECT * FROM deleted)
BEGIN
SELECT @Type = 'DELETE'
END

- 2,838
- 3
- 32
- 47

- 430
- 4
- 8
I believe nested ifs a little confusing and:
Flat is better than nested [The Zen of Python]
;)
DROP TRIGGER IF EXISTS AFTER_MYTABLE
GO
CREATE TRIGGER dbo.AFTER_MYTABLE ON dbo.MYTABLE AFTER INSERT, UPDATE, DELETE
AS BEGIN
--- FILL THE BEGIN/END SECTION FOR YOUR NEEDS.
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM INSERTED) AND EXISTS(SELECT * FROM DELETED)
BEGIN PRINT 'UPDATE' END
ELSE IF EXISTS(SELECT * FROM INSERTED) AND NOT EXISTS(SELECT * FROM DELETED)
BEGIN PRINT 'INSERT' END
ELSE IF EXISTS(SELECT * FROM DELETED) AND NOT EXISTS(SELECT * FROM INSERTED)
BEGIN PRINT 'DELETED' END
ELSE BEGIN PRINT 'NOTHING CHANGED'; RETURN; END -- NOTHING
END

- 6,203
- 2
- 45
- 47
After a lot of searching I could not find an exact example of a single SQL Server trigger that handles all (3) three conditions of the trigger actions INSERT, UPDATE, and DELETE. I finally found a line of text that talked about the fact that when a DELETE or UPDATE occurs, the common DELETED table will contain a record for these two actions. Based upon that information, I then created a small Action routine which determines why the trigger has been activated. This type of interface is sometimes needed when there is both a common configuration and a specific action to occur on an INSERT vs. UPDATE trigger. In these cases, to create a separate trigger for the UPDATE and the INSERT would become maintenance problem. (i.e. were both triggers updated properly for the necessary common data algorithm fix?)
To that end, I would like to give the following multi-trigger event code snippet for handling INSERT, UPDATE, DELETE in one trigger for an Microsoft SQL Server.
CREATE TRIGGER [dbo].[INSUPDDEL_MyDataTable]
ON [dbo].[MyDataTable] FOR INSERT, UPDATE, DELETE
AS
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with caller queries SELECT statements.
-- If an update/insert/delete occurs on the main table, the number of records affected
-- should only be based on that table and not what records the triggers may/may not
-- select.
SET NOCOUNT ON;
--
-- Variables Needed for this Trigger
--
DECLARE @PACKLIST_ID varchar(15)
DECLARE @LINE_NO smallint
DECLARE @SHIPPED_QTY decimal(14,4)
DECLARE @CUST_ORDER_ID varchar(15)
--
-- Determine if this is an INSERT,UPDATE, or DELETE Action
--
DECLARE @Action as char(1)
DECLARE @Count as int
SET @Action = 'I' -- Set Action to 'I'nsert by default.
SELECT @Count = COUNT(*) FROM DELETED
if @Count > 0
BEGIN
SET @Action = 'D' -- Set Action to 'D'eleted.
SELECT @Count = COUNT(*) FROM INSERTED
IF @Count > 0
SET @Action = 'U' -- Set Action to 'U'pdated.
END
if @Action = 'D'
-- This is a DELETE Record Action
--
BEGIN
SELECT @PACKLIST_ID =[PACKLIST_ID]
,@LINE_NO = [LINE_NO]
FROM DELETED
DELETE [dbo].[MyDataTable]
WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
END
Else
BEGIN
--
-- Table INSERTED is common to both the INSERT, UPDATE trigger
--
SELECT @PACKLIST_ID =[PACKLIST_ID]
,@LINE_NO = [LINE_NO]
,@SHIPPED_QTY =[SHIPPED_QTY]
,@CUST_ORDER_ID = [CUST_ORDER_ID]
FROM INSERTED
if @Action = 'I'
-- This is an Insert Record Action
--
BEGIN
INSERT INTO [MyChildTable]
(([PACKLIST_ID]
,[LINE_NO]
,[STATUS]
VALUES
(@PACKLIST_ID
,@LINE_NO
,'New Record'
)
END
else
-- This is an Update Record Action
--
BEGIN
UPDATE [MyChildTable]
SET [PACKLIST_ID] = @PACKLIST_ID
,[LINE_NO] = @LINE_NO
,[STATUS]='Update Record'
WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
END
END

- 189
- 2
- 3
while i do also like the answer posted by @Alex, i offer this variation to @Graham's solution above
this exclusively uses record existence in the INSERTED and UPDATED tables, as opposed to using COLUMNS_UPDATED for the first test. It also provides the paranoid programmer relief knowing that the final case has been considered...
declare @action varchar(4)
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
SET @action = 'U' -- update
ELSE
SET @action = 'I' --insert
END
ELSE IF EXISTS (SELECT * FROM DELETED)
SET @action = 'D' -- delete
else
set @action = 'noop' --no records affected
--print @action
you will get NOOP with a statement like the following :
update tbl1 set col1='cat' where 1=2

- 1,673
- 1
- 17
- 30
-
It seems that the first `END` is indented wrongly! (causing to question where the first `BEGIN` is closed) – S.Serpooshan Dec 31 '18 at 07:24
-
1the else if and final else contain single statements. the begin and end are really unnecessary since the IF/Else is a single statement. I did correct the indenting. Thanks for the help. – greg Jan 08 '19 at 17:22
DECLARE @ActionType CHAR(6);
SELECT @ActionType = COALESCE(CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED) THEN 'UPDATE' END,
CASE WHEN EXISTS(SELECT * FROM DELETED) THEN 'DELETE' END,
CASE WHEN EXISTS(SELECT * FROM INSERTED) THEN 'INSERT' END);
PRINT @ActionType;

- 3,488
- 2
- 21
- 21
Try this..
ALTER TRIGGER ImportacionesGS ON dbo.Compra
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
-- idCompra is PK
DECLARE @vIdCompra_Ins INT,@vIdCompra_Del INT
SELECT @vIdCompra_Ins=Inserted.idCompra FROM Inserted
SELECT @vIdCompra_Del=Deleted.idCompra FROM Deleted
IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NULL)
Begin
-- Todo Insert
End
IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NOT NULL)
Begin
-- Todo Update
End
IF (@vIdCompra_Ins IS NULL AND @vIdCompra_Del IS NOT NULL)
Begin
-- Todo Delete
End
END

- 81
- 1
- 4
I found a small error in Grahams otherwise cool solution:
It should be
IF COLUMNS_UPDATED() <> 0 -- insert or update
instead of > 0
probably because top bit gets interpreted as SIGNED integer sign bit...(?).
So in total:
DECLARE @action CHAR(8)
IF COLUMNS_UPDATED() <> 0 -- delete or update?
BEGIN
IF EXISTS (SELECT * FROM deleted) -- updated cols + old rows means action=update
SET @action = 'UPDATE'
ELSE
SET @action = 'INSERT' -- updated columns and nothing deleted means action=insert
END
ELSE -- delete
BEGIN
SET @action = 'DELETE'
END
This might be a faster way:
DECLARE @action char(1)
IF COLUMNS_UPDATED() > 0 -- insert or update
BEGIN
IF EXISTS (SELECT * FROM DELETED) -- update
SET @action = 'U'
ELSE
SET @action = 'I'
END
ELSE -- delete
SET @action = 'D'

- 7,807
- 20
- 69
- 114
-
4This way doesn't work for tables with large numbers of columns as columns_updated() returns a varbinary which is huge. So the "> 0" fails because the 0 defaults to an internally stored number much smaller than the value returned from columns_updated() – Graham Apr 05 '12 at 16:07
A potential problem with the two solutions offered is that, depending on how they are written, an update query may update zero records and an insert query may insert zero records. In these cases, the Inserted and Deleted recordsets will be empty. In many cases, if both the Inserted and Deleted recordsets are empty you might just want to exit the trigger without doing anything.

- 28,765
- 10
- 55
- 103

- 31
- 1
declare @insCount int
declare @delCount int
declare @action char(1)
select @insCount = count(*) from INSERTED
select @delCount = count(*) from DELETED
if(@insCount > 0 or @delCount > 0)--if something was actually affected, otherwise do nothing
Begin
if(@insCount = @delCount)
set @action = 'U'--is update
else if(@insCount > 0)
set @action = 'I' --is insert
else
set @action = 'D' --is delete
--do stuff here
End

- 2,247
- 1
- 27
- 37
-
1I wouldn't use COUNT(*) for performance reasons - it needs to scan the whole table. I would instead set a flag by using IF EXISTS(SELECT * FROM INSERTED), same for DELETED. I know normally there are only couple of rows affected, but why slow down the system. – Endrju Oct 05 '14 at 10:11
-
I was about to post something very similar as a solution. Its a little bit wordy, but very readable. Fair tradeoff. I also Like Grahms Solution above. – greg Mar 02 '18 at 18:52
This does the trick for me:
declare @action_type int;
select @action_type = case
when i.id is not null and d.id is null then 1 -- insert
when i.id is not null and d.id is not null then 2 -- update
when i.id is null and d.id is not null then 3 -- delete
end
from inserted i
full join deleted d on d.id = i.id
Since not all columns can be updated at a time you can check whether a particular column is being updated by something like this:
IF UPDATE([column_name])

- 11
- 1
-
1A challenge w/ this solution is you have to know a column name. Some of the others are designed such that you can just copy paste from a snippet library. Small point, but all things considered, a generic solution is better than a case specific solution. IMHO. – greg Mar 02 '18 at 18:53
just simple way
CREATE TRIGGER [dbo].[WO_EXECUTION_TRIU_RECORD] ON [dbo].[WO_EXECUTION]
WITH EXECUTE AS CALLER
FOR INSERT, UPDATE
AS
BEGIN
select @vars = [column] from inserted
IF UPDATE([column]) BEGIN
-- do update action base on @vars
END ELSE BEGIN
-- do insert action base on @vars
END
END

- 3,018
- 2
- 23
- 46

- 11
- 1
-
According to my SSMS IDE, your syntax isn't correct with how you're wrapping your logic in IF BEGIN - END ELSE BEGIN - END blocks. – Erutan409 Mar 03 '15 at 14:12
-
I like solutions that are "computer science elegant." My solution here hits the [inserted] and [deleted] pseudotables once each to get their statuses and puts the result in a bit mapped variable. Then each possible combination of INSERT, UPDATE and DELETE can readily be tested throughout the trigger with efficient binary evaluations (except for the unlikely INSERT or DELETE combination).
It does make the assumption that it does not matter what the DML statement was if no rows were modified (which should satisfy the vast majority of cases). So while it is not as complete as Roman Pekar's solution, it is more efficient.
With this approach, we have the possibility of one "FOR INSERT, UPDATE, DELETE" trigger per table, giving us A) complete control over action order and b) one code implementation per multi-action-applicable action. (Obviously, every implementation model has its pros and cons; you will need to evaluate your systems individually for what really works best.)
Note that the "exists (select * from «inserted/deleted»)" statements are very efficient since there is no disk access (https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6-9ab0-a255cdf2904a).
use tempdb
;
create table dbo.TrigAction (asdf int)
;
GO
create trigger dbo.TrigActionTrig
on dbo.TrigAction
for INSERT, UPDATE, DELETE
as
declare @Action tinyint
;
-- Create bit map in @Action using bitwise OR "|"
set @Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified
(select case when exists (select * from inserted) then 1 else 0 end)
| (select case when exists (select * from deleted ) then 2 else 0 end))
;
-- 21 <- Binary bit values
-- 00 -> No Rows Modified
-- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
-- 11 -> UPDATE <
-- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set
raiserror(N'@Action = %d', 10, 1, @Action) with nowait
;
if (@Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
;
-- do things for INSERT only
if (@Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
;
-- do things for UPDATE only
if (@Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
;
-- do things for DELETE only
if (@Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
;
-- do things for INSERT or UPDATE
if (@Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
;
-- do things for UPDATE or DELETE
if (@Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
;
-- do things for INSERT or DELETE (unlikely)
if (@Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
-- if already "return" on @Action = 0, then use @Action < 3 for INSERT or DELETE
;
GO
set nocount on;
raiserror(N'
INSERT 0...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;
raiserror(N'
INSERT 3...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;
raiserror(N'
UPDATE 0...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;
raiserror(N'
UPDATE 3...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t;
raiserror(N'
DELETE 0...', 10, 1) with nowait;
delete t from dbo.TrigAction t where asdf < 0;
raiserror(N'
DELETE 3...', 10, 1) with nowait;
delete t from dbo.TrigAction t;
GO
drop table dbo.TrigAction
;
GO

- 53
- 8
-
Thanks for this solution that feets in my context. Would you recommend a way to update the LastUpdated column of the updated / inserted row ? Would you also recommend a way to store on another table the ID of the deleted row (may be composed key) ? – Sébastien Apr 25 '17 at 14:22
In first scenario I supposed that your table have IDENTITY column
CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF @@ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE @action nvarchar(10)
SELECT @action = CASE WHEN COUNT(i.Id) > COUNT(d.Id) THEN 'inserted'
WHEN COUNT(i.Id) < COUNT(d.Id) THEN 'deleted' ELSE 'updated' END
FROM inserted i FULL JOIN deleted d ON i.Id = d.Id
In second scenario don't need to use IDENTITTY column
CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF @@ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE @action nvarchar(10),
@insCount int = (SELECT COUNT(*) FROM inserted),
@delCount int = (SELECT COUNT(*) FROM deleted)
SELECT @action = CASE WHEN @insCount > @delCount THEN 'inserted'
WHEN @insCount < @delCount THEN 'deleted' ELSE 'updated' END

- 16,594
- 6
- 37
- 44
-
I have same issue some one can help me. See the following link http://stackoverflow.com/questions/26043106/how-to-determine-if-insert-or-update/26043654#26043654 – Ramesh Somalagari Sep 25 '14 at 17:06
Quick solution MySQL
By the way: I'm using MySQL PDO.
(1) In an auto increment table just get the highest value (my column name = id) from the incremented column once every script run first:
$select = "
SELECT MAX(id) AS maxid
FROM [tablename]
LIMIT 1
";
(2) Run the MySQL query as you normaly would, and cast the result to integer, e.g.:
$iMaxId = (int) $result[0]->maxid;
(3) After the "INSERT INTO ... ON DUPLICATE KEY UPDATE" query get the last inserted id your prefered way, e.g.:
$iLastInsertId = (int) $db->lastInsertId();
(4) Compare and react: If the lastInsertId is higher than the highest in the table, it's probably an INSERT, right? And vice versa.
if ($iLastInsertId > $iMaxObjektId) {
// IT'S AN INSERT
}
else {
// IT'S AN UPDATE
}
I know it's quick and maybe dirty. And it's an old post. But, hey, I was searching for a solution a for long time, and maybe somebody finds my way somewhat useful anyway. All the best!

- 223
- 2
- 8
DECLARE @INSERTEDCOUNT INT,
@DELETEDCOUNT INT
SELECT @INSERTEDCOUNT = COUNT([YourColumnName]) FROM inserted
SELECT @DELETEDCOUNT = COUNT([YourColumnName]) FROM deleted
IF its updation
@INSERTEDCOUNT = 1
@DELETEDCOUNT = 1
if its insertion
@INSERTEDCOUNT = 1
@DELETEDCOUNT = 0
I've used those exists (select * from inserted/deleted)
queries for a long time, but it's still not enough for empty CRUD operations (when there're no records in inserted
and deleted
tables). So after researching this topic a little bit I've found more precise solution:
declare
@columns_count int = ?? -- number of columns in the table,
@columns_updated_count int = 0
-- this is kind of long way to get number of actually updated columns
-- from columns_updated() mask, it's better to create helper table
-- or at least function in the real system
with cte_columns as (
select @columns_count as n
union all
select n - 1 from cte_columns where n > 1
), cte_bitmasks as (
select
n,
(n - 1) / 8 + 1 as byte_number,
power(2, (n - 1) % 8) as bit_mask
from cte_columns
)
select
@columns_updated_count = count(*)
from cte_bitmasks as c
where
convert(varbinary(1), substring(@columns_updated_mask, c.byte_number, 1)) & c.bit_mask > 0
-- actual check
if exists (select * from inserted)
if exists (select * from deleted)
select @operation = 'U'
else
select @operation = 'I'
else if exists (select * from deleted)
select @operation = 'D'
else if @columns_updated_count = @columns_count
select @operation = 'I'
else if @columns_updated_count > 0
select @operation = 'U'
else
select @operation = 'D'
It's also possible to use columns_updated() & power(2, column_id - 1) > 0
to see if the column is updated, but it's not safe for tables with big number of columns. I've used a bit complex way of calculating (see helpful article below).
Also, this approach will still incorrectly classifies some updates as inserts (if every column in the table is affected by update), and probably it will classifies inserts where there only default values are inserted as deletes, but those are king of rare operations (at lease in my system they are). Besides that, I don't know how to improve this solution at the moment.

- 107,110
- 28
- 195
- 197
declare @result as smallint
declare @delete as smallint = 2
declare @insert as smallint = 4
declare @update as smallint = 6
SELECT @result = POWER(2*(SELECT count(*) from deleted),1) + POWER(2*(SELECT
count(*) from inserted),2)
if (@result & @update = @update)
BEGIN
print 'update'
SET @result=0
END
if (@result & @delete = @delete)
print 'delete'
if (@result & @insert = @insert)
print 'insert'
i do this:
select isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
1 -> insert
2 -> delete
3 -> update
set @i = isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
--select @i
declare @action varchar(1) = case @i when 1 then 'I' when 2 then 'D' when 3 then 'U' end
--select @action
select @action c1,* from inserted t1 where @i in (1,3) union all
select @action c1,* from deleted t1 where @i in (2)

- 840
- 9
- 23