Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TSql Trigger needs to fire only on columns whose values have changed

I wrote a trigger that needs to do some different work on a table based on which columns in a row actually updated. I accomplished this using

IF UPDATE(column-name)

That part works fine. It turns out, however, that there are other parts of the code that update rows by setting every single value whether the value actually changed or not and this causes the trigger to fire for parts that were "updated" but whose values did not actually change at all.

As changing the code that's causing this is probably not an option, is there an easier way to prevent this other than having to compare between the INSERTED and DELETED tables (in which case the IF UPDATEs are meaningless)?

like image 523
Ryan Elkins Avatar asked Jan 05 '10 17:01

Ryan Elkins


People also ask

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.

How do I know which column is updated in a trigger?

SQL Server COLUMNS_UPDATED() Function for Triggers. This function is used to know the inserted or updated columns of a table or view. It returns a VARBINARY stream that by using a bitmask allows you to test for multiple columns.

How do you determine if trigger is insert or update or delete?

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.

Can a select statement fire a trigger?

No there is no provision of having trigger on SELECT operation. As suggested in earlier answer, write a stored procedure which takes parameters that are fetched from SEECT query and call this procedure after desired SELECT query.


1 Answers

IF EXISTS (SELECT *
          FROM
             INSERTED I JOIN DELETED D ON I.Key = D.Key
          WHERE
             I.Col <> D.Col)
...

or use a table variable to cache thus to avoid repeated use of I and D.

SELECT
    CASE WHEN I.Col1 <> D.Col1 THEN 1 ELSE 0 END AS Col1Diff,
    CASE WHEN I.Col2 <> D.Col2 THEN 1 ELSE 0 END AS Col2Diff,
    ...
FROM
    INSERTED I JOIN DELETED D ON I.Key = D.Key

or combine ideas to test all changes up front and exit the trigger

like image 86
gbn Avatar answered Feb 07 '23 02:02

gbn