Fire trigger on updates (excluding certain fields change) - sql

I've defined my trigger like that:
CREATE TRIGGER [dbo].[trtablename]
ON [dbo].[tablename]
AFTER UPDATE
AS update tablename set row_version = row_version + 1
where id in (select id from inserted)
There's a field called Row_Status. It should be modified without incrementing row_version field. How do I make such a condition in the trigger?

You need to add a condition based on the UPDATE() function that can be called in triggers.
Something like:
CREATE TRIGGER [dbo].[trtablename] ON [dbo].[tablename]
AFTER UPDATE
AS
If not update(Row_Status)
begin
update tablename set row_version = row_version + 1
where id in (select id from inserted)
end
Depending on your table/columns and the likely UPDATE operations that might occur you may have to increase the complexity of the the check, but hopefully this points you in the correct direction.

The only down side to using the UPDATE function is that it will be true if the field is even mentioned in the update statement. Even if it is being set to itself.
CREATE TRIGGER [dbo].[trtablename]
ON [dbo].[tablename]
AFTER UPDATE
AS
IF NOT UPDATE (Row_Status)
update tablename set row_version = row_version + 1
where id in (select id from inserted)

Related

Create a trigger that updates a column in a table when a different column in the same table is updated - SQL

How to create a trigger that updates a column in a table when a different column in the same table is updated.
So far I have done the following which works when any new data is created. Its able to copy data from "Purchase Requisition" to "PO_Number" however when data has been modified in "Purchase Requisition" , no changes is made to "PO_Number" and the value becomes NULL. Any kind help will be seriously appreciated.
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2]
AFTER INSERT
AS BEGIN
UPDATE dbo.TheCat2 SET PO_Number=(select Purchase_Requisition from inserted) where DocNo= (Select DocNo from inserted);
END
You need to add 'UPDATE' as well as insert to the trigger, otherwise it will only execute on new data, not updated data. Also added 'top 1' to the select statements from the inserted table to allow this to be 'safe' on batch updates, however it will only update 1 record.
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2]
AFTER INSERT, UPDATE
AS BEGIN
UPDATE dbo.TheCat2 SET PO_Number=(select top 1 Purchase_Requisition from inserted) where DocNo= (Select top 1 DocNo from inserted);
END
This might do what you want:
Your trigger is altering all rows in TheCat2. Presumably, you only want to alter the new ones:
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2] AFTER INSERT
AS
BEGIN
UPDATE tc
SET PO_Number = Purchase_Requisition
FROM dbo.TheCat2 tc JOIN
inserted i
on tc.DocNo = i.DocNo ;
END;
However, perhaps a computed column is sufficient for your purposes:
alter table add PO_Number as Purchase_Requisition;

SQL Trigger update another table

I am newbie to triggers... can anybody help me with a trigger?
I have Table:
Name | Number
I want to write a trigger when my table receives a query like
update MyTable
set Number = Number + 1
where Name = 'myname'
When this query is running, the trigger should update another table for example:
Update MyTable 2
set Column = 'something'
where Name = 'myname (above name)
Thank you very much !
You will need to write an UPDATE trigger on table 1, to update table 2 accordingly.
Be aware: triggers in SQL Server are not called once per row that gets updated - they're called once per statement, and the internal "pseudo" tables Inserted and Deleted will contain multiple rows, so you need to take that into account when writing your trigger.
In your case, I'd write something like:
-- UPDATE trigger on "dbo.Table1"
CREATE TRIGGER Table1Updated
ON dbo.table1 FOR UPDATE
AS
BEGIN
-- update table2, using the same rows as were updated in table1
UPDATE t2
SET t2.Column = 'something'
FROM dbo.Table2 t2
INNER JOIN Inserted i ON t2.ID = i.ID
END
GO
The trick is to use the Inserted pseudo table (which contains the new values after the UPDATE - it has the exact same structure as your table the trigger is written for - here dbo.Table1) in a set-based fashion - join that to your dbo.Table2 on some column that they have in common (an ID or something).
create a trigger on table 1 for update:
CREATE TRIGGER dbo.update_trigger
ON table1
AFTER UPDATE
AS
BEGIN
DECLARE #Name VARCHAR(50)
SELECT #Name=Name FROM INSERTED
Update MyTable 2
SET Column = 'something'
WHERE Name = #Name
END
GO
try this ;)

T-SQL: How to deny update on one column of a table via trigger?

Question:
In our SQL-Server 2005 database, we have a table T_Groups.
T_Groups has, amongst other things, the fields ID (PK) and Name.
Now some idiot in our company used the name as key in a mapping table...
Which means now one may not alter a group name, because if one does, the mapping is gone...
Now, until this is resolved, I need to add a restriction to T_Groups, so one can't update the group's name.
Note that insert should still be possible, and an update that doesn't change the groupname should also be possible.
Also note that the user of the application & the developers have both dbo and sysadmin rights, so REVOKE/DENY won't work.
How can I do this with a trigger ?
CREATE TRIGGER dbo.yournametrigger ON T_Groups
FOR UPDATE
AS
BEGIN
IF UPDATE(name)
BEGIN
ROLLBACK
RAISERROR('Changes column name not allowed', 16, 1);
END
ELSE
BEGIN
--possible update that doesn't change the groupname
END
END
CREATE TRIGGER tg_name_me
ON tbl_name
INSTEAD OF UPDATE
AS
IF EXISTS (
SELECT *
FROM INSERTED I
JOIN DELETED D ON D.PK = I.PK AND ISNULL(D.name,I.name+'.') <> ISNULL(I.name,D.name+'.')
)
RAISERROR('Changes to the name in table tbl_name are NOT allowed', 16,1);
GO
Depending on your application framework for accessing the database, a cheaper way to check for changes is Alexander's answer. Some frameworks will generate SQL update statements that include all columns even if they have not changed, such as
UPDATE TBL
SET name = 'abc', -- unchanged
col2 = null, -- changed
... etc all columns
The UPDATE() function merely checks whether the column is present in the statement, not whether its value has changed. This particular statement will raise an error using UPDATE() but won't if tested using the more elaborate trigger as shown above.
This is an example of preserving some original values with an update trigger.
It works by setting the values for orig_author and orig_date to the values from the deleted pseudotable each time. It still performs the work and uses cycles.
CREATE TRIGGER [dbo].[tru_my_table] ON [dbo].[be_my_table]
AFTER UPDATE
AS
UPDATE [dbo].[be_my_table]
SET
orig_author = deleted.orig_author
orig_date = deleted.orig_date,
last_mod_by = SUSER_SNAME(),
last_mod_dt = getdate()
from deleted
WHERE deleted.my_table_id IN (SELECT DISTINCT my_table_id FROM Inserted)
ALTER TABLE [dbo].[be_my_table] ENABLE TRIGGER [tru_my_table]
GO
This example will lock any updates on SABENTIS_LOCATION.fk_sabentis_location through a trigger, and will output a detailed message indicating what objects are affected
ALTER TRIGGER dbo.SABENTIS_LOCATION_update_fk_sabentis_location ON SABENTIS_LOCATION
FOR UPDATE
AS
DECLARE #affected nvarchar(max)
SELECT #affected=STRING_AGG(convert(nvarchar(50), a.id), ', ')
FROM inserted a
JOIN deleted b ON a.id = b.id
WHERE a.fk_sabentis_location != b.fk_sabentis_location
IF #affected != ''
BEGIN
ROLLBACK TRAN
DECLARE #message nvarchar(max) = CONCAT('Update values on column fk_sabentis_location locked by custom trigger. Could not update entities: ', #affected);
RAISERROR(#message, 16, 1)
END
Some examples seem to be using:
IF UPDATE(name)
But this seems to evaluate to TRUE if the field is part of the update statement, even if the value itself has NOT CHANGED leading to false positives.

Prevent trigger from firing

I have the following trigger
First trigger:
ALTER TRIGGER [dbo].[DIENSTLEISTUNG_Update]
ON [dbo].[DIENSTLEISTUNG]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #intNewID int
INSERT INTO [DIENSTLEISTUNG]
(DESCRIPTION, QUANTITY,
PRICE, AZ_MO, AZ_DI,AZ_MI,AZ_DO,AZ_FR,
AZ_SA,AZ_SO,DIENSTLEISTUNGSART_ID,
UPDATE_USER, UPDATE_DATE,
PERMISSIONS, KONTRAKTPOSITION,ITEMNUMBER,
PRIORITY, VALID)
SELECT i.DESCRIPTION, i.QUANTITY, i.PRICE, i.AZ_MO,
i.AZ_DI,i.AZ_MI,i.AZ_DO,i.AZ_FR,
i.AZ_SA,i.AZ_SO,i.SERVICETYPE_ID, i.UPDATE_USER,GETDATE(),
i.PERMISSIONS, i.KONTRAKTPOSITION,i.ITEMNUMBER, i.PRIORITY, 'Y'
FROM INSERTED i
JOIN deleted d ON i.ID=d.ID
WHERE i.PRICE<>d.PRICE
or i.DESCRIPTION<>d.DESCRIPTION
IF ( UPDATE (PRICE) OR UPDATE (DESCRIPTION) )
UPDATE S
SET s.VALID = 'N'
FROM SERVICE s
JOIN INSERTED i ON I.ID = S.ID
IF UPDATE(PRIORITY)
UPDATE s
SET s.PRIORITY= i.PRIORITY
FROM SERVICE s
JOIN INSERTED i ON i.ID = s.ID
SET NOCOUNT OFF;
END
The first Trigger copies an entire row with a new ID if a change in the original row happens, also the trigger set a flag. The old row gets the flag VALID = 'N' and the new row gets the flag VALID = 'Y'. The trigger only creates a new row if PRICE or DESCRIPTION are updated. So far so good.
My problem is that if I want to update the PRIORITY in the new row the trigger fires again and sets the flag to VALID = 'N'. That should not happen. I want only to update the priority without creating a new row or update a another column.
Thanks for help
You cannot prevent a trigger from firing - if it's present and not disabled, it will fire. That's how triggers work.
What you can do is check inside your trigger which columns have been updated. So you could do something like this in your one single trigger:
CREATE TRIGGER [dbo].[DIENSTLEISTUNG_Update]
ON [dbo].[DIENSTLEISTUNG]
FOR UPDATE
AS
IF UPDATE(PRICE)
... (do what you need to do if PRICE is updated)...
IF UPDATE(DESCRIPTION)
... (do what you need to do if DESCRIPTION is updated)...
IF UPDATE(PRIORITY)
... (do what you need to do if PRIORITY is updated)...
Use the UPDATE() function to check whether a given column has been updated - and if so, act on it. See the MSDN docs on how to use the UPDATE() function.
You can make triggers fire only on certain columns or one colomn.
like this.
CREATE TRIGGER tr_something ON myTable
FOR INSERT, UPDATE
AS
IF UPDATE(myColumn)
BEGIN
-- do what you want
END
post below gives more details, seems I'm to slow :)
What you can do is set the context info of the session which you are in like this:
SET Context_Info 0x55555
And then in your trigger check for the context info to decide what to do:
DECLARE #Cinfo VARBINARY(128)
SELECT #Cinfo = Context_Info()
IF #Cinfo = 0x55555
RETURN

sql - Update Trigger to populate a ModifyDate field

I'm looking for an example of a good update trigger to update the ModifyDate field of a table.
It would be nice to handle the case where an update command updated more than one record in the table.
Is there a good template or tutorial for this?
Here's a cut and paste (and rename, to protect the innocent) of one I wrote quite some time ago (aka it works):
CREATE TRIGGER dbo.TR_iu_MyTable__LastUpdated
on dbo.MyTable
after insert, update
AS
SET NOCOUNT on
UPDATE dbo.MyTable
set LastUpdated = getdate()
where MyTableId in (select MyTableId from inserted)
UPDATE {tablename}
SET ModifyDate = GETDATE()
FROM inserted
WHERE {tablename}.{primarykey} = inserted.{primarykey}
Placed in a trigger tagged for INSERT and UPDATE actions will address your problem.
You could also do something similar for a CreateDate
UPDATE {tablename}
SET CreateDate = GETDATE()
FROM inserted
WHERE {tablename}.{primarykey} = inserted.{primarykey}
placed in a trigger tagged for INSERT action only.