How to make a Delete Query inside a Trigger? - sql

I am doing an after insert trigger on a table where I delete the rows that are incorrect, however, I am unable to do this and I can't find the correct syntax anywhere.
From what I understand, the table where the rows will be deleted from is in the FROM clause but I also need to use the inserted table. How do I do this?
I know this can be solved using an instead of insert trigger but I really want to know how to do this way.
DELETE
FROM promotion p, inserted i
WHERE <conditions>

You can try like this:
CREATE TRIGGER myTrigger ON dbo.MyTable
FOR INSERT
AS
SET NOCOUNT ON;
DELETE sometarget
FROM dbo.MyTable AS sometarget
JOIN inserted ON inserted.ID = sometarget.ID
WHERE <conditions>;
GO

Related

sql trigger after insert,update same table

My data is imported through the external system into the SQL Server.
I want to write a trigger that allows all data to be added to the database by default unless they have special conditions to be updated (they must be updated).
I mean, we should search on all input records and if we have some duplicate data (based on the above conditions), the insert operation should not be performed and only the new input data should replace the old data (Update Action).
Could you please help me?
Try this
CREATE TRIGGER TR_YourTable ON dbo.YourTable
FOR INSERT
AS
SET NOCOUNT ON;
DELETE tbl
FROM dbo.YourTable AS tbl
JOIN inserted ON inserted.ID = tbl.ID
WHERE inserted.ID in (select ID from dbo.YourTable);
GO

SQL trigger to add new records to a table with the same structure when an insertion is made

I am trying to create SQL trigger which adds a new record to the same table where an insertion is made through a web page. I am not exactly sure how to implement it but I tried the following query
CREATE trigger [dbo].[trgI_DealsDoneInserRecord]
on [dbo].[Terms]
after insert
As
Insert into DealsDone
(Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product)
VALUES
(SELECT Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product FROM inserted)
END
The above query threw an error in the SELECT statement in VALUES.
May I know a way to implement this?
Try this:
CREATE trigger [dbo].[trgI_DealsDoneInserRecord]
ON [dbo].[Terms]
AFTER INSERT
As
BEGIN
INSERT INTO DealsDone
(Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product)
SELECT Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product FROM inserted
END
While I generally advocate against using SELECT *, in this case it seems like a benefit:
By not specifying the fields you can automatically account for changes in the tables without having to update this trigger if you add or remove or even rename fields.
This will help you catch errors in schema updates if one of the tables is updated but the other one isn't and the structure is then different. If that happens, the INSERT operation will fail and you don't have to worry about cleaning up bad data.
So use this:
CREATE TRIGGER [dbo].[trgI_DealsDoneInserRecord]
ON [dbo].[Terms]
AFTER INSERT
AS
SET NOCOUNT ON;
INSERT INTO [DealsDone]
SELECT *
FROM inserted;
There is an syntax issue, and also you are missing BEGIN
The basic syntax is
INSERT INTO table2 (column_name(s))
SELECT column_name(s)
FROM table1;
So try this
CREATE trigger [dbo].[trgI_DealsDoneInserRecord]
on [dbo].[Terms]
after insert
As
BEGIN
Insert into DealsDone
(Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product)
SELECT Company,Grade,Term,Pipeline,[Index],Volume,Price,[Type],CounterParty,
TermID,GradeID,CPID,Locked,Product
FROM inserted
END
Refer:- http://technet.microsoft.com/en-us/library/ms188263(v=sql.105).aspx

SQL Server 2005 'INSTEAD OF' DELETE Trigger - Not deleting Source Records

I created a trigger in SQL Server 2005 that inserts records into a history table whenever a deletion occurs in the source table. The records are getting inserted, but they are not getting deleted from the source table.
Here is my trigger:
CREATE TRIGGER TRG_EdiHistory
ON dbo.EDI10000
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
SET IDENTITY_INSERT dbo.EDI10500 ON;
INSERT INTO EDI10500(File_Id, Tp_Id, File_Name, File_Size, File_Data, Rec_Date, Content_Type, Update_Flag)
SELECT
File_Id, Tp_Id, File_Name, File_Size, File_Data,
Rec_Date, Content_Type, Update_Flag
FROM
DELETED
END
GO
I had to use an INSTEAD OF trigger because my tables contains Image type columns.
Please if anyone has any idea why this is happening.
Thank you.
* UPDATE *
CREATE TRIGGER TRG_EdiHistory
ON dbo.EDI10000
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
SET IDENTITY_INSERT dbo.EDI10500 ON;
INSERT INTO EDI10500 ([File_Id],Tp_Id,[File_Name],File_Size
,File_Data,Rec_Date,Content_Type,Update_Flag)
SELECT [File_Id], Tp_Id, [File_Name], File_Size, File_Data,
Rec_Date, Content_Type, Update_Flag
FROM DELETED
DELETE FROM dbo.EDI10000
WHERE EXISTS (SELECT 1
FROM DELETED
WHERE [FILE_ID] = dbo.EDI10000.[File_Id])
END
GO
Instead of Triggers , fire Instead of the triggering action. In your Case this instead of Trigger fires and Inserts data into your history table.
Note this trigger fires instead of the Delete command. So if you also want to Delete rows you will need to add Delete statement inside this trigger.
Having said this I think instead of Instead Trigger if you simply define an After Trigger with same definition as your this instead of trigger will makes things pretty simple. It will delete the rows from table and then insert rows into your history table as you are expecting it to work.
Update
Since you have mentioned you cannot use Image Data type inside an After Trigger in sql server 2005, I am not aware of this limitation. Well in this case you can simply add a delete statement inside your this existing instead of trigger.
DELETE FROM dbo.table
WHERE EXISTS (SELECT 1
FROM deleted
WHERE Pk_Column = table.PK_Column)
Instead of delete replaces the standard action of the DELETE statement.
http://technet.microsoft.com/en-us/library/ms191208(v=sql.105).aspx
Have a look here how to do what you really want:
How to create a before delete trigger in SQL Server?

Delete - Trigger

I wrote this trigger below. it is generating Error at:
Where UAssignment_Rights.user_id =i.user_id
from Inserted i
I want that when any row Deletes from Users table. It should also delete Deleted User Details from UAssignment_Rights Table.
Here in Image above Normalized Table is named as UAssignment_Rights
CREATE TRIGGER Trigger_Update ON Users
FOR DELETE
AS
set nocount on
DELETE
FROM UAssignment_Rights
Where UAssignment_Rights.user_id =i.user_id
from Inserted i
PRINT 'AFTER INSERT trigger fired.'
Can anyone answer my this question! Thank you.
Your syntax is wrong for deleting with a JOIN. Try this instead:
CREATE TRIGGER Trigger_Update ON Users
FOR DELETE
AS
SET NOCOUNT ON;
DELETE UR
FROM UAssignment_Rights UR
INNER JOIN Deleted D
ON UR.[user_id] = D.[user_id]
PRINT 'AFTER INSERT trigger fired.'
Also, this is for SQL Server (which seems to be the actual RDBMS that you are using, I don't know why you tagged this question with MySQL too)

two triggers on insert of same table

Here is one very interesting problem. I am using SQL Server 2008.
I have two triggers on one common table say 'CommonTable'. one trigger is on update and other one is on insert/update/delete.
In first trigger "Trigger1", I do the checks/rollback sometime change the new inserted value based on business logic.
here is sample code
-
CREATE TRIGGER [dbo].[Trigger1] ON [dbo].[CommonTable]
FOR UPDATE
UPDATE [CommonTable]
SET
[StatusCode] = 'New Value'
WHERE
[RecId] = 'rec id value'
In second trigger "Trigger2", I store the new inserted/deleted/updated value from 'CommonTable' table to another table 'CommonTable_History' for history tracking purpose.
here is sample code
-
CREATE TRIGGER [dbo].[Trigger2] ON [dbo].[CommonTable]
FOR INSERT, UPDATE, DELETE
--based on logic read the value from DELETED or INSERTED table and store in other table.
SELECT #RowData = (SELECT * FROM DELETED AS [CommonTable] WHERE [RecId] = #RowRecId FOR XML AUTO, BINARY BASE64 , ELEMENTS)
--and then insert #RowData in 'CommonTable_History' table.
With the help of 'sp_settriggerorder', I have set the order of execution of these triggers, so first "Trigger1" get executed and then "Trigger2".
Second trigger "Trigger2" works well for insert/delete values. It works fine for new inserted value if new inserted values has not been changed by first trigger "Trigger1".
But if in some cases, inserted values has been changed in "Trigger1". say [StatusCode] = 'New Value' and old values was 'Old Value' then "Trigger2" still store the 'Old Value' instead of 'New Value'.
Why because "Trigger1" change the value but that value still has not been store in database and before that "Trigger2" get executed on Insert.
Now my requirement is, here I want to store "New Value".
So I thought, lets make "Trigger2" to use "AFTER" keywords. But "FOR" and "AFTER" behave same could not solve the problem.
Then I thought, lets make "Trigger2" to use "INSTEAD OF" keyword. But "INSTEAD OF" gives following error
"Cannot CREATE INSTEAD OF DELETE or INSTEAD OF UPDATE TRIGGER. This is because the table has a FOREIGN KEY with cascading DELETE or UPDATE."
I can not remove FOREIGN KEY with cascading DELETE or UPDATE for table 'CommonTable'.
Please let me know if you people have any other alternate solution.
-Vikram Gehlot
I think your second trigger needs to use the values from the actual table, not the inserted/deleted tables to populate the log table - inserted/deleted will always have the unaltered, original values, while your altered values will appear in the table. Make the second trigger an "After" trigger, so you will not have to use the sp_settriggerorder. Like this, for example:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[trg_Trig1]
ON [dbo].[TestTable]
FOR INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
update TestTable
set [value] = 10
where [value] = 25
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[trg_Trig2]
ON [dbo].[TestTable]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
insert into log_TestTable
(id, description, [value])
select tt.id, tt.description, tt.[value]
from inserted i
LEFT JOIN TestTable tt
ON tt.id = i.id
END
It may not be the cleanest solution but can you simply combine the two triggers into one? That way both pieces of SQL would know about each other's changes.
Your second trigger appears to me as if it would not work properly is mulitple records are inserted in a set-based operations unloess you use a loop which is poor choice in a trigger. Fix that first!
Instead of select * from deleted, why not join the deleted or inserted table to the original table and take the values from there (except for the id value which you get from deleted or inserted, that should give you the most current values of all fileds and if you add other trigger logic later wil not break.