I have a table in SQL Server which houses snapshots of all data to track changes in status of the source table tbl_D_project
. If this status changes or a new record is added in tbl_D_project
, a trigger should start and the line will be copied to the snapshot table.
I wrote two triggers based on another question I found here. One trigger for the update and one for the insert. My questions are:
Is there a more efficient way? Can I somehow combine the two in one, so After Insert, Update?
Multiple users are submitting data at the same time. How long does the data stay in the inserted table? Is there a possibility that if two users submit data, the trigger will be fired twice, so the lines will be copied twice to the snapshot table?
After update trigger:
ALTER TRIGGER [dbo].[tr_copysnapshot_update]
ON [CDB].[dbo].[tbl_D_project]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
INNER JOIN
Deleted D ON s.opp_ID = D.Opp_ID
WHERE
D.[Status] <> I.[Status]
END
After insert trigger:
ALTER TRIGGER [dbo].[tr_copysnapshot_insert]
ON [CBD].[dbo].[tbl_D_project]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID,
Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
WHERE
S.[Opp_ID] = I.[Opp_ID]
END
SQL update trigger only when column is modified
Advertisement
Answer
Yes you can combine the triggers, just use a LEFT JOIN
to the memory resident table deleted
, and change your where clause so that you only add a row if the status changes (Update) or there is no record in deleted (insert), i.e.
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
LEFT JOIN
Deleted D ON s.opp_ID = D.Opp_ID
WHERE
(D.[Status] <> I.[Status] OR d.Opp_ID IS NULL)
For your second question, what you are describing is not possible, two users can’t do the same update at the same time, even if it is just micro seconds apart it would still do one then the other (each would have it’s own inserted/deleted table), so yes this would always fire the trigger twice.
If both users do the same update, then your where clause stipulating that the status must have changed would prevent a second insert. If you wanted to extend this to capture records when other columns have changed, but not if nothing has changed, you could use the following WHERE
clause:
WHERE NOT EXISTS (SELECT i.* INTERSECT SELECT d.*)