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
Related
I have created a single trigger to catch all insert, update and delete operations in a replica table but in case of update, two rows are inserted one with before update values and another row with after update values but it is not working as expected.
I have tried all possible ways to do it. Now, I want to know whether I should use transaction at trigger level for update operation or should try something else.
ALTER TRIGGER [dbo].[trgAfterInsertUpdateDelete_xyz] ON [dbo].[xyz]
FOR UPDATE,INSERT, DELETE
AS
declare #accountID int;
declare #billingDate date;
declare #amount decimal(18, 2);
---- Get data from inserted/ updated
select #accountID = i.AccountID from inserted i;
select #billingDate=i.BillingDate from inserted i;
select #amount=i.Amount from inserted i;
-- Insert Case
IF EXISTS( SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted)
BEGIN
insert into xyz_Audit
(AccountID, BillingDate, Amount, Audit_Action)
values(#accountID,#billingDate,#amount,'INSERT');
END
-- Update Case
IF EXISTS( SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
BEGIN
INSERT INTO xyz_Audit
(AccountID, BillingDate, Amount, Audit_Action)
SELECT d.AccountID, d.BillingDate, d.Amount,
'BeforeUpdate' FROM Inserted i
INNER JOIN Deleted d ON i.ID = d.ID
INSERT INTO xyz_Audit
(AccountID, BillingDate, Amount,Audit_Action)
values(#accountID,#billingDate,#amount,'AfterUpdate');
END
-- Delete Case
IF EXISTS( SELECT * FROM deleted) AND NOT EXISTS(SELECT * FROM inserted)
BEGIN
INSERT INTO xyz_Audit
(AccountID, BillingDate, Amount, Audit_Action)
select accountID,billingDate,amount, 'DELETE'
from deleted
END
I expected that if 9 records are updated then there should be before and after update values for all rows but sometimes it skips. As you can see for Inst.8 there should be before and after rows but it has captured only before row and then insert but in actual there was no row deleted and inserted, only updation was done. Sometime out of 9, it pick only before rows not after update rows or sometime 2 or 3 after update rows not before update rows.
your trigger assuming that only one row will be affected for insert / update / delete operatons. Which means the inserted or deleted may contains multiple rows
and the following part does not handle that.
---- Get data from inserted/ updated
select #accountID = i.AccountID from inserted i;
select #billingDate=i.BillingDate from inserted i;
select #amount=i.Amount from inserted i;
Actually you don't required the above at all. You should just insert into the Audit table directly from the inserted or deleted table
For example the "INSERT CASE" should be
-- Insert Case
IF EXISTS( SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted)
BEGIN
insert into xyz_Audit (AccountID, BillingDate, Amount, Audit_Action)
select AccountID, BillingDate, Amount, Audit_Action= 'INSERT'
from inserted;
END
similarly you need to change accordingly for the Update section. And you are already doing it correctly for the delete section
I've been trying to make a trigger work. My aim is to have a trigger check if a value exist on another table on insertion to a table.
Below is the trigger that is not working:
CREATE TRIGGER trigger1
ON table1
AFTER INSERT
AS
declare #tId int
IF EXISTS ((Select #tId from inserted i join table2 on i.tId=table2.Id
join table3 on i.tId=table3.tId
where i.tId NOT IN (SELECT tId from table3)
and table2.ApplicationDate > '2018-01-31 00:00:00.0000000'
and table2.cnumber is NOT NULL))
BEGIN
ROLLBACK transaction
SET NOCOUNT ON;
END
GO
Can anyone point me in the right direction please.
Your question is unclear.
These parts in combination makes no sense:
join table3 on i.tId=table3.tId
where i.tId NOT IN (SELECT tId from table3)
-> NO MATCHING ROWS!
The simple solution for checking both tables without dependency between it:
CREATE TRIGGER trigger1
ON table1 AFTER INSERT
AS
BEGIN
IF (EXISTS (SELECT Id FROM table2 WHERE Id IN(SELECT tId FROM Inserted))
OR EXISTS (SELECT Id FROM table3 WHERE Id IN(SELECT tId FROM Inserted))) BEGIN
ROLLBACK;
END
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
Using Triggers:
We have 2 tables like named table1 and table2
if we insert anything into table1 instead of that it should get inserted into table2 and must compare with table1 whether already that row or data existing..
if existed then it should get updated into table1 else it should get inserted as new row into table1..
You can use following trigger to identify insert or update or deleted state of your table
CREATE TRIGGER Audit
ON dbo.Employee
FOR INSERT, UPDATE, DELETE
AS
IF (SELECT COUNT(*) FROM inserted) > 0
BEGIN
IF (SELECT COUNT(*) FROM deleted) > 0
BEGIN
-- update!
INSERT AuditEmployee
(EmployeeID, UserName, Operation)
SELECT EmployeeID, SUSER_SNAME(), 'U'
FROM inserted
END
ELSE
BEGIN
-- insert!
INSERT AuditEmployee
(EmployeeID, UserName, Operation)
SELECT EmployeeID, SUSER_SNAME(), 'I'
FROM inserted
END
END
ELSE
BEGIN
-- delete!
INSERT AuditEmployee
(EmployeeID, UserName, Operation)
SELECT EmployeeID, SUSER_SNAME(), 'D'
FROM deleted
END
GO
If a user changes table HelloWorlds, then I want 'action they did', time they did it, and a copy of the original row insert into HelloWorldsHistory.
I would prefer to avoid a separate triggers for insert, update, and delete actions due to the column lengths.
I've tried this:
create trigger [HelloWorlds_After_IUD] on [HelloWorlds]
FOR insert, update, delete
as
if ##rowcount = 0
return
if exists (select 1 from inserted) and not exists (select 1 from deleted)
begin
insert into HelloWorldHistory (hwh_action, ..long column list..)
select 'INSERT', helloWorld.id, helloWorld.text ... and more from inserted
end
else
if exists (select 1 from inserted) and exists (select 1 from deleted)
begin
insert into HelloWorldHistory (hwh_action, ..long column list..)
select 'UPDATE', helloWorld.id, helloWorld.text ... and more from deleted
end
else
begin
insert into HelloWorldHistory (hwh_action, ..long column list..)
select 'DELETE', helloWorld.id, helloWorld.text ... and more from deleted
end
end
I've never seen an insert appear, but I've seen updates. I'm going to try 3 separate triggers, though maintaining the column lists will not be fun.
try something like this:
CREATE TRIGGER YourTrigger ON YourTable
AFTER INSERT,UPDATE,DELETE
AS
DECLARE #HistoryType char(1) --"I"=insert, "U"=update, "D"=delete
SET #HistoryType=NULL
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
BEGIN
--UPDATE
SET #HistoryType='U'
END
ELSE
BEGIN
--INSERT
SET #HistoryType='I'
END
--handle insert or update data
INSERT INTO YourLog
(ActionType,ActionDate,.....)
SELECT
#HistoryType,GETDATE(),.....
FROM INSERTED
END
ELSE IF EXISTS(SELECT * FROM DELETED)
BEGIN
--DELETE
SET #HistoryType='D'
--handle delete data, insert into both the history and the log tables
INSERT INTO YourLog
(ActionType,ActionDate,.....)
SELECT
#HistoryType,GETDATE(),.....
FROM DELETED
END
--ELSE
--BEGIN
-- both INSERTED and DELETED are empty, no rows affected
--END
You need to associate (match) the rows in the inserted and deleted columns. Something like this should work better.
create trigger [HelloWorlds_After_IUD] on [HelloWorlds]
FOR insert, update, delete
as
insert into HeloWorldsHistory
select 'INSERT', helloWorld.id, helloWorld.text ... and more
from inserted
where myKeyColumn not in (select myKeyColumn from deleted)
insert into HeloWorldsHistory
select 'DELETE', helloWorld.id, helloWorld.text ... and more
from deleted
where myKeyColumn not in (select myKeyColumn from inserted)
insert into HeloWorldsHistory
select 'UPDATE', helloWorld.id, helloWorld.text ... and more
from inserted
where myKeyColumn in (select myKeyColumn from deleted)