I have two triggers on one table, one fires on insert and updates the row with additional info from other tables
CREATE TRIGGER [dbo].[eTteamTg]
ON [dbo].[entryTable]
AFTER INSERT
AS
BEGIN
UPDATE entryTable
SET shiftTeam = (SELECT TOP 1 shiftTeamMemb.teamId
FROM shiftTeamMemb
WHERE shiftTeamMemb.personalNumber = i.personalNumber)
FROM entryTable
INNER JOIN inserted i ON i.ID = entryTable.ID
END
And second one fires after update
CREATE TRIGGER [dbo].[eThistoryUpdTg] ON [dbo].[entryTable]
AFTER update
AS
BEGIN
INSERT INTO eThistory(my columns)
SELECT
*, HOST_Name() + ' ' + SUSER_NAME() + ' Upd', GETDATE()
FROM
deleted
END
What I need to do is to not fire AFTER UPDATE trigger when I am updating the rows with AFTER INSERT trigger. Is it possible ?
I suggest you to merge this two triggers into one:
CREATE TRIGGER [dbo].[eTteamTg]
ON [dbo].[entryTable]
AFTER INSERT, UPDATE
AS
BEGIN
UPDATE entryTable
SET shiftTeam = (SELECT TOP 1 shiftTeamMemb.teamId
FROM shiftTeamMemb
WHERE shiftTeamMemb.personalNumber = i.personalNumber)
FROM entryTable
INNER JOIN inserted i ON i.ID = entryTable.ID
INSERT INTO eThistory(my columns)
SELECT
*, HOST_Name() + ' ' + SUSER_NAME() + ' Upd', GETDATE()
FROM
deleted
END
Then after INSERT, it will update shiftTeam and `deleted1 will not be used.
After UPDATE, it will update shiftTeam and use deleted to get previous (even to above update) values.
Or if you don't need to update shiftTeam in case of UPDATE on this table you can add IF statement:
CREATE TRIGGER [dbo].[eTteamTg]
ON [dbo].[entryTable]
AFTER INSERT, UPDATE
AS
BEGIN
IF (SELECT COUNT(*) FROM deleted) = 0 --That means it was INSERT
BEGIN
UPDATE entryTable
SET shiftTeam = (SELECT TOP 1 shiftTeamMemb.teamId
FROM shiftTeamMemb
WHERE shiftTeamMemb.personalNumber = i.personalNumber)
FROM entryTable
INNER JOIN inserted i ON i.ID = entryTable.ID
END
INSERT INTO eThistory(my columns)
SELECT
*, HOST_Name() + ' ' + SUSER_NAME() + ' Upd', GETDATE()
FROM
deleted
END
Implement your second trigger like this,
CREATE TRIGGER [dbo].[eThistoryUpdTg] ON [dbo].[entryTable]
AFTER UPDATE
AS
BEGIN
INSERT INTO eThistory (my columns)
SELECT *
,HOST_Name() + ' ' + SUSER_NAME() + ' Upd'
,GETDATE()
FROM deleted d
WHERE NOT EXISTS (
SELECT TOP 1 shiftTeamMemb.teamId
FROM shiftTeamMemb
INNER JOIN inserted I ON i.personalNumber = shiftTeamMemb.personalNumber
INNER JOIN entryTable E ON E.ID = I.ID
WHERE shiftTeamMemb.personalNumber = i.personalNumber
)
END
Related
I have a table called tbl_A with a column called DESC.
The old application inserts and updates values in this DESC column like 'H PP' or 'H CC' or 'CR BB'.
I want to replace those inserted values with 'HPP' or 'HCC' or 'CRBB'. Or you could say I want to remove the space between strings.
This is my trigger so far:
CREATE TRIGGER TrgUpd
ON Tbl_A
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE Tbl_A
SET desc = 'HPP'
FROM Tbl_A A
INNER JOIN UPDATED u ON a.id = u.id
WHERE u.desc = 'H PP'
END
There is no UPDATED pseudo table in a SQL Server trigger. In your case, you'd have to inspect the Deleted pseudo table which contains the "old" values - those before the UPDATE happened. Also: you can just trim out the spaces - something like this:
CREATE TRIGGER TrgUpd
ON Tbl_A
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE A
SET [Desc] = REPLACE(d.[Desc], ' ', '')
FROM Tbl_A A
INNER JOIN Deleted d ON a.id = d.id
END
UPDATE: if you want to explicitly specify what strings to replace - use this code:
CREATE TRIGGER trg_upd_inrt
ON [dbo].[tbl_A]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE A
SET [Desc] = CASE i.[Desc]
WHEN 'HR DD' THEN 'HRDD'
WHEN 'H PP' THEN 'HPP'
WHEN 'RPT AR' THEN 'RPTARIN'
WHEN 'APPP PPLE' THEN 'APPLE'
WHEN 'HR DD' THEN 'HRDD'
END
FROM tbl_A a
INNER JOIN inserted i ON a.id = i.id
END
I am trying to put table b value when table a inserted but nothing effects on table b. Its like there is no trigger. Do you have any suggestion. I have tried below but no result.
alter trigger triggername on tablea after insert as
begin
update tablea set valuetablea_a = valuetablea_b where id = (select distince id from inserted)
end
begin
update tableb set valuetableb_a = (select valuetablea_a from tablea where id = (select distincd id from Inserted))
where date = (select distinct date from Inserted)
end
Try this:
ALTER TRIGGER triggername ON tablea AFTER INSERT AS
BEGIN
UPDATE a
SET
valuetablea_a = I.valuetablea_b
FROM tablea A
INNER JOIN inserted I
ON A.Id = I.Id
UPDATE B
SET
valuetableb_a = A.valuetablea_a
FROM tableb B
INNER JOIN tablea
ON 1=1 AND EXISTS
(
SELECT 1 FROM inserted WHERE ID = A.ID AND [Date] = B.DATE
)
end
In the first update, you are giving this
update tablea set valuetablea_a = valuetablea_b
Which means From TableA update the value from column valuetablea_b to valuetablea_a for each row that was updated. Instead of getting the values from the Updated valuetablea_b column
2nd Update updates the values in TableB.valuetableb_a by matching the Id and Date fileds in the updated records
I have defined a trigger on a table that is triggered
AFTER INSERT, DELETE, UPDATE
There are cases where the trigger fires, with both INSERTED AND DELETED tables being empty. How can this be possible?
For the records, that's the trigger
CREATE TRIGGER [dbo].[AuditUsersTrigger] ON [dbo].[Users]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON
DECLARE #type nchar(1), #hasChanges bit
SET #hasChanges = 1
IF EXISTS (SELECT * FROM INSERTED)
IF EXISTS (SELECT * FROM DELETED)
BEGIN
SELECT #type = 'U'
IF EXISTS (
SELECT *
FROM INSERTED i
INNER JOIN DELETED d ON
i.Name = d.Name AND
i.Pwd = d.Pwd AND
...
) SELECT #hasChanges = 0
END
ELSE
SELECT #type = 'I'
ELSE
SELECT #type = 'D'
IF #type = 'D' OR (#type = 'U' AND #hasChanges = 1)
BEGIN
INSERT AuditUsers (
New, Id, Name, ...
)
SELECT
0, Id, Name, ...
FROM DELETED
IF #type = 'D'
BEGIN
INSERT AuditUsers (New)
SELECT 1
END
END
IF #type = 'I' OR (#type = 'U' AND #hasChanges = 1)
BEGIN
IF #type = 'I'
BEGIN
INSERT AuditUsers (New)
SELECT 0
END
INSERT AuditUsers (
New, Id, Name, ...
)
SELECT
0, Id, Name, ...
FROM INSERTED
END
IF Trigger_Nestlevel() < 2
BEGIN
DECLARE #clientId TABLE (id INT)
DECLARE #clientCode NVARCHAR(50), #shopId INT;
IF #type = 'I' OR #type = 'U'
BEGIN
SELECT #clientCode = ClientCode, #shopId = ShopId FROM INSERTED;
INSERT INTO #clientId SELECT id FROM Clients WHERE code = #clientCode;
IF NOT EXISTS (SELECT 1 FROM #clientId)
BEGIN
INSERT Clients (name, code, active, shopId) OUTPUT INSERTED.id INTO #clientId
VALUES (#clientCode, #clientCode, 1, #shopId);
END
UPDATE Users SET ClientId = (SELECT TOP 1 id FROM #clientId) WHERE ClientCode = #clientCode;
END
END
END
This is documented behaviour
DML triggers execute when a user tries to modify data through a data manipulation language (DML) event. DML events are INSERT, UPDATE, or DELETE statements on a table or view. These triggers fire when any valid event is fired, regardless of whether or not any table rows are affected.
If you have a recurring loop, whereby table A has a trigger that affects table B, and table B has a trigger that affects table A, you can manage this using TRIGGER_NESTLEVEL, or by checking if either inserted or deleted contain any rows before actually doing anything.
I am using SQL Server 2008.
Assuming I have Table A which is a transaction table. And Table B which is a history table.
Whenever a row is inserted or updated in Table A, a new row should be inserted in Table B.
The Status column of Table B should change to INSERTED or UPDATED respectively.
How to handle this from a single trigger?
What you're asking for is quite simple:
CREATE TRIGGER TR_TableA_IU ON dbo.TableA FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT dbo.TableB (Column1, Column2, Status)
SELECT
I.Column1,
I.Column2,
CASE WHEN EXISTS (SELECT * FROM Deleted) THEN 'UPDATED' ELSE 'INSERTED' END
FROM Inserted I;
If you also wanted to handle deletions, that can be done in a single statement, too:
CREATE TRIGGER TR_TableA_IUD ON dbo.TableA FOR INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
INSERT dbo.TableB (Column1, Column2, Status)
SELECT
I.Column1,
I.Column2,
CASE WHEN EXISTS (SELECT * FROM Deleted) THEN 'UPDATED' ELSE 'INSERTED' END
FROM
Inserted I
UNION ALL
SELECT
D.Column1,
D.Column2,
'DELETED'
FROM Deleted D
WHERE NOT EXISTS (
SELECT * FROM Inserted
);
Wow, there are a lot of outright-wrong and semi-wrong (at least in being overcomplicated) answers given so far.
Assuming that both tables:
has an "Id" column as primary key.
has the same schema, except that history table has an extra "Status" column at the end.
You can create a trigger like this:
CREATE TRIGGER dbo.TableA_InsUpd
ON dbo.TableA
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
Insert Into TableB
Select i.*, 'INSERTED'
From inserted i
Where not exists ( Select * From deleted d Where d.Id = i.Id )
Update B
Set [Status] = 'UPDATED',
Field1 = i.Field1,
Field2 = i.Field2
From TableB B
Inner Join inserted i On i.Id = B.Id
Where exists ( Select * From deleted d Where d.Id = i.Id )
Update B
Set [Status] = 'DELETED'
From TableB B
Inner Join deleted d On d.Id = B.Id
Where not exists ( Select * From inserted i Where i.Id = d.Id )
END
Here is a SqlFiddle with the complete code
(Note this will fail if a record Id is deleted and then inserted again)
Try this code
CREATE TRIGGER YouTriggerName
ON TableA
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
DECLARE #type NVarChar(15)=
CASE when not exists(SELECT * FROM inserted)
THEN 'Deleted'
WHEN exists(SELECT * FROM deleted)
THEN 'Updated'
ELSE
'Inserted'
END
/*
TableB should contains all the columns of TableA
OR tweak it to suit your need
*/
IF #type = 'Deleted' BEGIN
INSERT INTO TableB
SELECT *, #type Stat FROM deleted
END
ELSE BEGIN
INSERT INTO TableB
SELECT *, #type Stat FROM inserted
END
END
NOTE
You will get this error if TableB has identity on since we use (select *)
An explicit value for the identity column in table 'TableB' can only be specified when a column list is used and IDENTITY_INSERT is ON.
this is tested.here employee and employee have same table structure.0 means updated and 1=inserted,2=deleted
Alter trigger trgTest on dbo.employee
AFTER INSERT, UPDATE,Delete
as
Begin
Set noCount on
if exists(select e.id from deleted e inner join inserted i on e.ID=i.id )
Begin
insert into Employee1
select id,name,0 from inserted
End
else if exists(select e.id from Employee1 e inner join deleted d on e.ID=d.id)
Begin
insert into Employee1
select id,name,2 from deleted
End
else
Begin
insert into Employee1
select id,name,1 from inserted
End
End
I wish to make a modification (Set Deleted = 1) to rows being inserted into my table CustomerContact if the SELECT statement returns more than 0.
I have the following, but it remains untested:
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
DECLARE #numrows INT;
/* Determine if order matches criteria for marking customer contact as DELETED immediately */
SELECT #numrows = COUNT(*)
FROM [Order] o
JOIN OrderMeterDetail om
ON o.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
AND o.orderid IN (SELECT OrderID FROM INSERTED);
/* If the order matches the criteria, mark the customer contact as deleted */
IF (#numrows >= 1)
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM INSERTED);
END
Within my IF statement, I am using FROM INSERTED, assuming that this will return the newly inserted id for the record that was created by the insert.
I have two questions about this statement:
Will this part of the statement perform an UPDATE just the record
that was just inserted into CustomerContact?
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM INSERTED);
Is this the way that would be deemed correct to make a change to a row that has just been inserted based on the result of a SELECT statement?
CustomerContactID is an auto-incrementing primary key column.
You say "Just the record that was inserted". Inserted can contain more than one record. If there is only one, then your trigger will function as you expect. But if there is more than one, it won't.
I would rewrite your logic into a single update statement along the lines of...
Update CustomerContact
Set Deleted = 1
From CustomerContact
inner join inserted on CustomerContact.CustomerContactID = inserted.CustomerContactID
inner join orders on inserted.OrderID = orders.OrderID
where
-- some criteria.
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
DECLARE #numrows INT;
/* Determine if order matches criteria for marking customer contact as DELETED immediately */
-- Get all the records into a temp table
SELECT * INTO #Temp
FROM inserted
Declare #ID int;
SELECT #numrows = COUNT(*)
FROM [Order] o
JOIN OrderMeterDetail om
ON o.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
AND o.orderid IN (SELECT OrderID FROM #Temp);
IF (#numrows >= 1)
BEGIN
WHILE EXISTS (SELECT TOP 1 * FROM #Temp)
BEGIN
SELECT TOP 1 #ID = ID FROM #Temp
/* If the order matches the criteria, mark the customer contact as deleted */
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM #Temp WHERE ID = #ID);
DELETE FROM #Temp WHERE ID = #ID
END
END
DROP TABLE #Temp
END
I think you can do something like this, tweak the code to futher suit for needs, hope this will help.
Here is the final solution that I used to solve this issue:
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
UPDATE CustomerContact
SET Deleted = 1
FROM CustomerContact cc
JOIN inserted i
ON cc.CustomerContactID = i.CustomerContactID
JOIN [Order] o
ON i.OrderID = o.OrderID
JOIN OrderMeterDetail om
ON i.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
END