SQL server triggers : Deleted table empty after update - sql-server

I have a database A, table t with a transactional replication to a database B table t
on B.t there is a trigger
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE OR ALTER TRIGGER [dbo].[synchro_trigger]
ON [dbo].[t]
FOR INSERT, UPDATE
AS
BEGIN
-- update case
IF EXISTS ( SELECT 0 FROM Deleted )
...
when running an update on A.t :
update A.t set field1='1' where id=?
the value is replicated then the trigger is called and SELECT 0 FROM Deleted exist;
the trigger does its job.
When updating ALL fields on table t (some get a different value, some get the same value)
update A.t set field1='1', field2='1', ... where id=?
the values (which are differents) are replicated then the triggrer is called BUT SELECT 0 FROM Deleted doesn't exist.
so the trigger does nothing, it is not what I want.
In case of update the previous row value is supposed to be inside Deleted, right?
How it is possible that the trigger doesn't receive the previous value inside the Delete table ?
Note :
it looks like the same issue as : SQLServer Update Trigger with empty DELETED logical table

Related

SQL Server Trigger after insert update and delete

Want to create a trigger where I have two table "A" and "B" and table "A" has already some records in it so i want to write a trigger in table "B" where i want to check condition if table "A" has already the record exist which is inserting then do not insert or fire a trigger of table "B" if record is not exist in table "A" then fire a trigger and insert a record into the table.
As SQL Server doesn't have BEFORE INSERT triggers to alter that insertion before its done, I would use an INSTEAD OF INSERT trigger (your trigger code is executed instead of the usual insertion, so you can add your checks and/or additional actions).
This trigger sample will only insert rows in A when they don't exist in B:
CREATE TRIGGER tr_a_ioi ON A
INSTEAD OF INSERT
AS BEGIN
insert into A
select I.*
from inserted I
left join B on B.PK_Field = I.PK_Field
where B.PK_Field is null -- no corresponding row is found in B
END
You can write similar INSTEAD OF UPDATE and INSTEAD OF DELETE triggers to do additional checks or actions when trying to update or delete rows in A.

SQL AFTER INSERT,UPDATE Trigger with condition if update specific column

I would like to create a trigger that inserts new datasets into the FREE08 table (see example code) either after insert on FREE03. This part works. But i also want to insert new dataset into FREE08 only if specific column (FK2) of FREE03 is updated. Thought this works with the "IF UPDATE(FK2) statement in the trigger.
What happens is i got a new dataset in FREE08 everytime i have any update in FREE03.
How can i get that?
Thanks for your support
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[Einsatzhistorie Wechsler]
ON [dbo].[FREE03]
AFTER INSERT,UPDATE
AS
SET NOCOUNT ON;
IF UPDATE(FK2)
BEGIN
INSERT INTO FREE08
(
FK1,FK2,TEXT3,DATE1,TEXT2,DATE4
)
Select FK2,FK1,ID,DATE1,TEXT1,DATE11 From inserted
end
I've never found a real use for the UPDATE function, since it tells you whether a column was subject to UPDATE (I.e. appeared in the SET clause), not whether data actually changed. In addition, of course, triggers fire once per statement, not once per row, so your trigger may be dealing with a mixture of rows, some of which had their FK2 changed and some not.
It's usually better to use deleted and compare the previous/current values:
CREATE TRIGGER [dbo].[Einsatzhistorie Wechsler]
ON [dbo].[FREE03]
AFTER INSERT,UPDATE
AS
SET NOCOUNT ON;
INSERT INTO FREE08
(
FK1,FK2,TEXT3,DATE1,TEXT2,DATE4
)
Select i.FK2,i.FK1,i.ID,i.DATE1,i.TEXT1,i.DATE11
From inserted i
left join deleted d
on
i.ID = d.ID and
i.FK2 = d.FK2
where d.ID is null
Here I've assumed a) that ID represents an immutable primary key for the table and b) That FK2 isn't nullable.

Trigger after update to update linked server table

Basically I have an app where upon column field change (update) another table on a linked server gets updated.
After modifying reference number through an app, this value gets updated in Table_A.
Now I wan't to trigger update of Table_B if Table_A column field reference number is updated.( only check for update of this very field )
USE [SRV1]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[BenRef_UPDATE]
ON [dbo].[Table_A]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
IF UPDATE(refNum)
UPDATE [EXPSRV1].[OPR].[protected].[TransferServiceArrangement]
SET PaymentDetailsBeneficiaryReferenceNumber = i.refNum
FROM inserted i
INNER JOIN deleted d
ON d.party= i.party
END;
Right now I am unable to update Table_A when Trigger is created, no change will occur, when I drop the trigger and modify number the change reflects on the Table_A.
What did I miss ?

Create a trigger that won't let updating the primary key columns

I have a table that has a composite primary key made from 3 columns, let's say A, B, C. I want to create a trigger that on UPDATE will check that these three columns won't be changed. This is what I have so far, but it doesn't seem to work:
CREATE TRIGGER TableTrigger
ON Table
AFTER INSERT, UPDATE AS
BEGIN
IF (EXISTS (SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted))
BEGIN
-- Update Operation
IF (SELECT COUNT(*) FROM inserted WHERE A IS NOT NULL OR B IS NOT NULL OR C IS NOT NULL) > 0
BEGIN
RAISERROR('Error, you cannot change Primary Key columns', 16, 1)
ROLLBACK
RETURN
END
END
I was expecting that if I update some values in a table, in inserted the values for the columns I don't update to be NULL, but it's not like that. I read somewhere that I need to look both in inserted and deleted to see if these values changed. So my question is this, can I check this without using a cursor?
Thank you.
You could do
CREATE TRIGGER TableTrigger
ON Table
AFTER UPDATE AS
BEGIN
IF UPDATE(A) OR UPDATE(B) OR UPDATE(C)
BEGIN
RAISERROR('Error, you cannot change Primary Key columns', 16, 1)
ROLLBACK
RETURN
END
END
Or deny update permissions on those columns.
Both approaches would deny any attempt to update the PK columns irrespective of whether or not the values actually change. SQL Server does not have row level triggers and unless there is an IDENTITY column in the table (guaranteed immutable) there is no reliable way to tell in a trigger if the PK was actually updated.
For example the INSERTED and DELETED tables in an UPDATE trigger on the table below would be identical for both the UPDATE statements.
CREATE TABLE T(C INT PRIMARY KEY);
INSERT INTO T VALUES (1),(-1)
/*Both values swapped*/
UPDATE T SET C = -C
/*Both values left the same*/
UPDATE T SET C = C

SQL Server Update Trigger

I have never used triggers before in SQL server and I have looked around online but haven't found an answer to my question. Basically I am trying to write an Trigger that will run after a record has been updated in a table. This trigger will then update two additional tables based on the record that was updated in the first table.
The primary table with the trigger on it will be updating one record using a query like this:
UPDATE E.SM_T_RList
SET IsActive = 0
WHERE Guid = #Guid
I then want the trigger to do something like this:
ALTER TRIGGER [E].[IsActiveUpdate]
ON [E].[SM_T_RList]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE E.SM_T_BInfo
SET IsActive = 0
WHERE Guid = #Guid
UPDATE E.SM_T_RMachines
SET IsActive = 0
WHERE GUID = #GUID
END
The Guid that I want updated is being used by the primary table. But I can't figure out how I get the #Guid that I want updated into the trigger? Please help.
Thanks
Both the answers already posted suffer from the same problem - they're marking the other rows as Inactive, whenever any update occurs on your base table
Something like:
ALTER TRIGGER [E].[IsActiveUpdate]
ON [E].[SM_T_RList]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE E.SM_T_BInfo
SET IsActive = 0
WHERE Guid IN (SELECT Guid FROM INSERTED where IsActive=0)
UPDATE E.SM_T_RMachines
SET IsActive = 0
WHERE Guid IN (SELECT Guid FROM INSERTED where IsActive=0)
END
Would be more appropriate
Triggers in SQL Server operate on sets of rows not individual rows. You access these via the inserted and deleted pseudo tables. Assuming that you might want the value of isactive to cascade when previously inactive rows were made active you could use something like this.
ALTER TRIGGER [E].[IsActiveUpdate]
ON [E].[SM_T_RList]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE E.SM_T_BInfo
SET IsActive = i.IsActive
FROM INSERTED i JOIN E.SM_T_BInfo e
ON e.Guid = i.Guid
UPDATE E.SM_T_RMachines
SET IsActive = i.IsActive
FROM INSERTED i JOIN E.SM_T_BInfo e
ON e.Guid = i.Guid
END

Resources