Sql Trigger to add new row when table update - sql

I am new to sql triggers and learning as developing triggers for asp.net application.i am having case where I need to first save table and then edit the same table - this edit create new row in different table but the the problem is every time I edit the table it create new row in different table I want to create row in different table for only first edit.
Dividing my problem for readability.
I have two tables:
Table A and table B
I have written trigger on table A that add row in table B.
Problem:
Every time I edit row in table A a new row get added to table B. (So every edit create new row)
Required result:
I want my trigger to add ONLY one row in table B for the first edit in table A but not for subsequent edits.
I am using update triggers.
Any example with code would be great
Thanks you much in advance .
Create TRIGGER [dbo].[triggerName] ON [dbo].[databaseName]
For Update
As
Begin
DECLARE #i int
DECLARE #d int
DECLARE #action char(6)
DECLARE #Car VARCHAR(20)
IF (##ROWCOUNT = 0) RETURN
SELECT #i = Count(*) From Inserted
SELECT #d = Count(*) From Deleted
SELECT #action = CASE
WHEN (#i <> 0) and (#d <> 0) THEN 'UPDATE'
WHEN (#i = 0) and (#d <> 0) THEN 'DELETE'
WHEN (#i <> 0) and (#d = 0) THEN 'INSERT'
End
SELECT #Car = A From inserted
IF #action = 'UPDATE' AND #Car in ('BMW')
Begin
INSERT INTO Tableb (c,d,f)
Select c,d,f from inserted
End

Your trigger has some flaws in it.
First, You don't need to test if it was fired because of update, insert or delete. The trigger is specified for update, so inserts and deletes will not fire it anyway.
Second, SELECT #Car = A From inserted will raise an error whenever you update more then one row in the table.
Third, As you said, this will insert a record in tableB for every update, while you want it to insert a record only for the first update done (I assume one for the first update on any row, so if you update row 1 then insert, update row 2 then another insert, and update row 1 again don't insert).
I would write it like this:
Create TRIGGER [dbo].[triggerName] ON [dbo].[tableName]
For Update
As
Begin
INSERT INTO Tableb (c,d,f)
Select c,d,f
from inserted i
left join Tableb t ON(i.c = t.c and i.d = t.d and i.f = t.f)
where t.id is null -- or some other non-nullable column
and i.a = 'BMW'
End

You can modify your SQL trigger to execute only after INSERT
CREATE TRIGGER dbo.myTable_Insert
ON dbo.myTable
AFTER INSERT
AS
It is possible to create SQL trigger to run after insert, update or delete as seen in the referred tutorial

Related

To write a trigger for INSERT as well as UPDATE in SQL

I have written a trigger which should fire when an INSERT or UPDATE happens to a table "COST_HDR" and the DML should update one of the columns of this table i.e. "CMPL_STS" to 'C'.
My trigger is not working as expected. If the CMPL_STS is directly updated to 'C' as a new record, trigger works as expected. But if it is updated to 'D' as a new record and then to 'C' as an update, trigger fails to insert any record in TMP_XNS table.
Can anyone check what is wrong:
CREATE TRIGGER MyTrigger
ON [COST_HDR]
AFTER INSERT, UPDATE
AS
BEGIN
DECLARE #UpdtStamp DATETIME = GETUTCDATE()
--
IF UPDATE (CMPL_STS)
BEGIN
INSERT INTO [TMP_XNS]
(
HDR_UID,
UPDT_STAMP
)
SELECT I.HDR_UID,
#updtStamp
FROM INSERTED I
LEFT OUTER JOIN DELETED D
ON D.HDR_UID = I.HDR_UID
AND ISNULL(I.CMPL_STS,'N') <> ISNULL(D.CMPL_STS,'N')
WHERE I.CMPL_STS = 'C'
END
--
END
GO

Delete trigger and getting field from another table

I have this delete trigger on an SQL database. The record deletes currently and gets written to an audit table. I have been asked to include in this history table a field from another table that is related to the record being deleted based on SurveyID. I thought I could do something like
select #Status = Status from table where Survey = deleted.Survey
But this is incorrect syntax.
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
Declare #SurveyId int
Declare #StudentUIC varchar(10)
Declare #Status varchar(10)
select #SurveyId = deleted.SurveyID,
#StudentUIC = deleted.StudentUIC
from deleted
select #Status = Status from tbly when SurveyID = deleted.SurveyID
insert into fupSurveyAudit
values(#SurveyId,#StudentUIC,#Status)
End
Arrgh. I think you want this insert in your trigger (and nothing else):
insert into fupSurveyAudit(SurveyId, StudentUIC, status)
select d.SurveyId, d.StudentUIC, y.status
from deleted d left join
tbly y
on d.SurveyId = y.SurveyId;
Notes:
deleted could contain more than one row, so assuming that it has one row can lead to a run-time error or incorrect results.
A left join is needed in case there is no matching row for the status.
You should always include the columns in an insert
Your archive table should have additional columns, such as an identity column and the date of the insert, which are set automatically (and hence not explicitly part of the insert).
Triggers are fired once for each statement (Delete,insert,update) not for each row inside the statement.
You cannot use variables here because when multiple lines are deleted from the table only one line will be inserted in the Audit table because the variable can only hold one value.
You just need a simple insert from the deleted table into the Audit table something like this....
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
insert into fupSurveyAudit(SurveyId, StudentUIC,[Status])
select d.SurveyID
,d.StudentUIC
,y.[Status]
from deleted d
INNER JOIN tbly y ON y.SurveyID = deleted.SurveyID
End
Try this
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
insert into fupSurveyAudit -- Better listed the column list here
select
d.SurveyID, d.StudentUIC, y.Status
from
deleted d JOIN tbly y ON d.SurveyID = y.SurveyID
End

Trigger to delete prior duplicate records in the table

I need to write a trigger based on the following condition
Before inserting a record in the table, I need to compare the value of one column to the existing records, and if records found then I need to delete those records having same column value in the already existing records, and then need to insert that new record.
Please let me know how to achieve this.
Thanks
CREATE TRIGGER [dbo].[CustomInsert_Trigger] ON [dbo].[Realtimebookingcount]
INSTEAD OF INSERT AS
BEGIN
DECLARE #Flag INT
SELECT #Flag = Booking_NUM FROM inserted
IF (SELECT COUNT(1) FROM Realtimebookingcount
WHERE Booking_NUM = #Flag) > 0
BEGIN
DELETE FROM Realtimebookingcount
WHERE Realtimebookingcount.Booking_NUM = #Flag
END
INSERT INTO Realtimebookingcount
SELECT * FROM inserted
END

After insert not working

all id columns has auto_increment
In my trigger:
ALTER trigger [dbo].[mytrig]
on [dbo].[requests]
after INSERT, UPDATE
as
begin
declare #MyId1 int
set #MyId1 = (select Id from inserted)
declare #MyId2 int
declare #MyId3 int
if (select column1 from inserted) = 1
begin
insert into [dbo].[contracts] select column1,column2,column3 .... from inserted
set #MyId2 = SCOPE_IDENTITY()
insert into [dbo].[History] select column1,column2,column3 .... from inserted
set #MyId3 = SCOPE_IDENTITY()
insert into [dbo].[contracts_depts](Id_Contract ,column5) select #MyId2,column6 from request_depts where Id_request=#MyId1
insert into [dbo].[History_depts] (Id_InHistory,column5) select #MyId3,column6 from request_depts where Id_request=#MyId1
end
end
#MyId1 returns value only after update but not after insert. Do I have to use scope_identity() or something ?
Your main issue is: you're assuming the triggers is called once per row - that is NOT the case!
The trigger is called once per statement, and if your statement affects multiple rows, the Inserted pseudo table will contain multiple rows - so your statement here
set #MyId1 = (select Id from inserted)
really isn't going to work - it will select one arbitrary row (out of however many there are).
You'll need to rewrite your trigger to take this fact into account! Assume that Inserted contains 100 rows - how do you want to deal with that? What are you trying to achieve? Triggers don't return values - they will record into an audit table, or update other rows, or something like that ....

Sometimes SQL Server trigger is not firing

I created a trigger on my recharge table. It updates the balance of onaccountregistry table.
But sometimes when inserting rows into my recharge table it is not firing the trigger. Then values are mismatch. This recharge table insert rows every time.
I created the trigger as follows. This is not a replicated table. I'm using SQL Server 2008 Enterprise edition.
Please help me solve this matter
CREATE TRIGGER [dbo].[RechargeRefund]
ON [dbo].[ISRecharge]
FOR INSERT
AS
declare #tin char(9)
declare #depocd char(1)
declare #oldvalue money
declare #newvalue money
begin
select #tin = inserted.tin_subtin from inserted
select #depocd = inserted.updatetype from inserted
select #newvalue = inserted.DepositAmt from inserted
select #oldvalue = Totdeposit from ISOnAcctRegistry where tin_subtin = #tin
end
if #depocd ='1'
begin
update ISOnAcctRegistry
set Totdeposit = #oldvalue + #newvalue
where tin_subtin = #tin
end
if #depocd ='2'
begin
update ISOnAcctRegistry
set Totdeposit = #oldvalue - #newvalue
where tin_subtin = #tin
end
GO
As #marc points out, writing assuming a single row in inserted is bad - it can even be possible for your 3 selects from inserted to assign values to your 3 variables from 3 different (arbitrary) rows from inserted.
What you probably want is:
update i1
set Totdeposit = Totdesposit + t2.Total
from ISOnAcctRegistry i1
inner join
(select
tin_subtin,
SUM(CASE updatetype
WHEN 1 THEN DepositAmt
WHEN 2 THEN -DepositAmt
ELSE 0 END) as Total
from inserted
group by tin_subtin) t2
on
i1.tin_subtin = t2.tin_subtin
But you might be able to replace this work (and this column in ISOnAcctRegistry) with an indexed view built on ISRecharge - with some limitations, you can build a view that automatically performs a SUM across the rows in ISRecharge, and SQL Server would take responsibility for maintaining the value in the background for you.
Obviously, at present, your trigger doesn't account for any UPDATE or DELETE activity on ISRecharge. An indexed view would.
Well, of course it won't work - you're assuming that the trigger fires once per row inserted.
But that's NOT the case.
The trigger fires once per INSERT batch, and the pseudo-table Inserted might contain multiple rows!
If you did get an INSERT with more than one row - which row did your statements here select ?
select #tin = inserted.tin_subtin from inserted
select #depocd = inserted.updatetype from inserted
select #newvalue = inserted.DepositAmt from inserted
select #oldvalue = Totdeposit from ISOnAcctRegistry where tin_subtin = #tin
You need to rewrite your trigger so that it will handle multiple rows in Inserted - then it'll work every time.