Problem: I wrote a trigger that is supposed to update the INVOICE table after an INSERT into the LINE table but it won't update the invoice table. The trigger fires but the Update statement block won't execute.
I debugged while I executed the INSERT into the line table and found out as soon as the it gets to the UPDATE statement it jumps over it and doesn't run that code. I have been trying to figure this out for a couple of days now.
Here is my trigger code
ALTER TRIGGER [dbo].[trgInvoiceInsert] ON [dbo].[LINE]
AFTER INSERT
AS
declare #linUnits numeric(9,2);
declare #linPrice numeric(9,2);
declare #invNum int;
select #linUnits = LINE_UNITS from inserted;
select #linPrice = LINE_PRICE from inserted;
select #invNum = INV_NUMBER from inserted;
BEGIN
UPDATE i --From here it jumps to the start of the next Update
SET INV_SUBTOTAL = INV_SUBTOTAL + (#linUnits * #linPrice)
FROM dbo.INVOICE as i
WHERE i.INV_NUMBER = #invNum
UPDATE i
SET INV_TOTAL = INV_SUBTOTAL + INV_TAX
FROM dbo.INVOICE as i
WHERE i.INV_NUMBER = #invNum
PRINT 'Trigger fired Successfully.'
END
Well, using a statement like this:
select #linUnits = LINE_UNITS from inserted;
indicates that you're assuming that the trigger fires per row - it does not.
SQL Server triggers are fired once per statement - so if your statement inserts multiple rows into the Line table, your trigger will fire once for the complete statement, but the Inserted pseudo table will contain multiple rows of data.
So you need to rewrite your trigger to take that into account - the Inserted table can (and will!) contain multiple rows - and your trigger code needs to deal with that.
Related
How to create a trigger that updates a column in a table when a different column in the same table is updated.
So far I have done the following which works when any new data is created. Its able to copy data from "Purchase Requisition" to "PO_Number" however when data has been modified in "Purchase Requisition" , no changes is made to "PO_Number" and the value becomes NULL. Any kind help will be seriously appreciated.
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2]
AFTER INSERT
AS BEGIN
UPDATE dbo.TheCat2 SET PO_Number=(select Purchase_Requisition from inserted) where DocNo= (Select DocNo from inserted);
END
You need to add 'UPDATE' as well as insert to the trigger, otherwise it will only execute on new data, not updated data. Also added 'top 1' to the select statements from the inserted table to allow this to be 'safe' on batch updates, however it will only update 1 record.
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2]
AFTER INSERT, UPDATE
AS BEGIN
UPDATE dbo.TheCat2 SET PO_Number=(select top 1 Purchase_Requisition from inserted) where DocNo= (Select top 1 DocNo from inserted);
END
This might do what you want:
Your trigger is altering all rows in TheCat2. Presumably, you only want to alter the new ones:
ALTER TRIGGER [dbo].[PO_Number_Trigger]
ON [dbo].[TheCat2] AFTER INSERT
AS
BEGIN
UPDATE tc
SET PO_Number = Purchase_Requisition
FROM dbo.TheCat2 tc JOIN
inserted i
on tc.DocNo = i.DocNo ;
END;
However, perhaps a computed column is sufficient for your purposes:
alter table add PO_Number as Purchase_Requisition;
I need to update a column in table after any record is added in same table
Here is my sql code
CREATE TRIGGER [dbo].[EmployeeInsert]
ON [dbo].[APP_Employees]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #EmployeeID AS bigint
SELECT #EmployeeID = ID FROM inserted
UPDATE [dbo].[APP_Employees]
SET [EmployeeTotalNumberOfAnnualLeave] = [EmployeeBalanceTheInitialNumberOfDaysOfAnnualLeaveIn]
WHERE ID=#EmployeeID
END
GO
and showing error
Msg 2714, Level 16, State 2, Procedure EmployeeInsert, Line 17
There is already an object named 'EmployeeInsert' in the database.
The error you're getting is because you have that trigger already, in your database. So if you want to create it again, you need to first drop the existing trigger (or use ALTER TRIGGER instead of CREATE TRIGGER to modify the existing trigger).
BUT: your fundamental flaw is that you seem to expect the trigger to be fired once per row - this is NOT the case in SQL Server. Instead, the trigger fires once per statement, and the pseudo table Inserted might contain multiple rows.
Given that that table might contain multiple rows - which one do you expect will be selected here??
SELECT #EmployeeID = ID FROM inserted
It's undefined - you might get the values from arbitrary rows in Inserted.
You need to rewrite your entire trigger with the knowledge the Inserted WILL contain multiple rows! You need to work with set-based operations - don't expect just a single row in Inserted !
-- drop the existing trigger
DROP TRIGGER [dbo].[EmployeeInsert]
GO
-- create a new trigger
CREATE TRIGGER [dbo].[EmployeeInsert]
ON [dbo].[APP_Employees]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
-- update your table, using a set-based approach
-- from the "Inserted" pseudo table which CAN and WILL
-- contain multiple rows!
UPDATE [dbo].[APP_Employees]
SET [EmployeeTotalNumberOfAnnualLeave] = i.[EmployeeBalanceTheInitialNumberOfDaysOfAnnualLeaveIn]
FROM Inserted i
WHERE [dbo].[APP_Employees].ID = i.ID
END
GO
I want to copy the contents of a column into another column in the same table. Therefore, I created this trigger:
ALTER TRIGGER [dbo].[kennscht_copy_to_prodverpt]
ON [dbo].[Stammdaten]
AFTER INSERT
AS
UPDATE Stammdaten
SET PRODVERPT = (SELECT KENNSCHT FROM INSERTED)
WHERE SNR = (SELECT SNR FROM INSERTED);
But when I use an UPDATE on the table to update KENNSCHT to a different value, PRODVERPT is not updated as well. Now, you could argue that is because the trigger is on AFTER INSERT and not AFTER UPDATE, but when I change it so it's triggered by UPDATE and INSERT, whenever I update any row, I get an error message from SQL Server
Cannot update row because it would make the row not unique or update multiple rows (2 rows) [sic]
What is going on here? Either the trigger doesn't do anything, or it's messing up the whole table, making it un-updateable.
Update: I also tried the following trigger:
UPDATE s
SET s.PRODVERPT = i.KENNSCHT
FROM Stammdaten s
INNER JOIN INSERTED i ON i.SNR = s.SNR;
But it has exactly the same behaviour. If I use only AFTER INSERT, nothing changes and if I use AFTER INSERT, UPDATE I get the error message above.
Update 2: There are no multiple rows in the table, I already checked that because I thought it might be connected to the issue.
If you run this trigger as an AFTER UPDATE trigger, it runs recursively, since it always issues another UPDATE statement against the same table, which leads to another execution of the trigger.
To work around this, you either need to make the update trigger an INSTEAD OF UPDATE trigger or test if the KENNSCHT column was modified at all. For the latter you can use the UPDATE() function like this:
ALTER TRIGGER [dbo].[kennscht_copy_to_prodverpt_after_update]
ON [dbo].[Stammdaten]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (UPDATE(KENNSCHT))
BEGIN
UPDATE s
SET s.PRODVERPT = i.KENNSCHT
FROM Stammdaten s
INNER JOIN INSERTED i ON i.SNR = s.SNR
END
END
I have a trigger on a table that is something like this:
ALTER TRIGGER [shoot_sms]
ON [dbo].[MyTable]
AFTER INSERT
AS
begin
declare #number bigint
declare #body varchar(50)
declare #flag int
select #number=number,#body=body,#flag=flag from inserted
if(#flag=0)
begin
insert into temptable (number,body,status)
select #number,#body,'P'
end
end
Now I am making two entries in mytable as below:
insert into mytable(number, body, flag)
values(3018440225, 'This is test', 0)
insert into mytable(number, body, flag)
values(3018440225, 'This is test', 0)
I execute these queries at a time, but for both of the queries the trigger fires only once and performs the task for the first query only.
How can I make it work for both insert statements?
Just an idea but put a GO statement between those two insert statements and that might cause the trigger to fire twice.
You should probably rewrite your trigger to handle multiple row inserts I think.
Here is your query converted. You should get two rows now.
ALTER TRIGGER [shoot_sms]
ON [dbo].[MyTable]
AFTER INSERT
AS
begin
insert into temptable (number,body,status)
select number,body,'P'
from inserted
where flag = 0
end
Also notice your trigger is much simpler now.
Since those two statements are in one SQL batch, the trigger will (by design) only fire once.
Triggers don't fire once per row - they fire once per statement! So if you have an INSERT or UPDATE statement that affects more than one row, your trigger will have more than one row in the Inserted (and possibly Deleted) pseudo tables.
The way you wrote this trigger is really not taking into account that Inserted could contain multiple rows - what row do you select from the Inserted table if you're inserting 20 rows at once?
select #number = number, #body = body, #flag = flag from inserted
You need to change your trigger to take that into account!
I have two triggers After Insert or Update and Instead of Insert. It appears that the after trigger is not running or sending the correct data.
I have verified the correct operation of Z_UpdateStageTable stored procedure and the Instead of Insert trigger. Removing the Instead of Insert trigger doesn't have any affect. The After Insert, Update trigger was working correctly at one time, I haven't made any changes to it. I have tried deleting it and adding it, but it still doesn't run or have the correct data.
Any Ideas?
Instead of Insert:
ALTER TRIGGER [DeleteExistingFilter]
ON [dbo].[Z_MobileSyncFilters]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM Z_MobileSyncFilters WHERE UserID = (SELECT UserID FROM INSERTED);
INSERT INTO Z_MobileSyncFilters
SELECT *
FROM INSERTED;
END
After Insert, Update:
TRIGGER [UpdateStageTable]
ON [dbo].[Z_MobileSyncFilters]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #AllWos AS VARCHAR(5000);
DECLARE #PmWos AS VARCHAR(5000);
DECLARE #RepWos AS VARCHAR(5000);
SET #AllWos = (SELECT AllWos FROM INSERTED);
SET #RepWos = (SELECT AllWos FROM INSERTED);
SET #PmWos = (SELECT AllWos FROM INSERTED);
EXEC Z_UpdateStageTable #AllWos;
EXEC Z_UpdateStageTable #RepWos;
EXEC Z_UpdateStageTable #PmWos;
END
Is there a typo in the SET part of the AFTER trigger? You're selecting the same thing into three different variables.
Rather than confirming the behavior of Z_UpdateStageTable, I'd try to replace it with something dirt simple (a parameterless sql statement, say) to test whether the trigger's being called. It's possible that the sproc's not being called with what you think it's being called with.
You can add PRINT statements to the trigger and manually insert from ManagementStudio/Enterprise Manager to see where the trigger fails.
I see a problem when you insert multiple records in a single statement, as the SELECT FROM Inserted will return more than 1 record.
You can also update the SET statement to SELECT #Var = AllWos FROM Inserted
Hold on a second, if userid is your PK then Z_MobileSyncFilters will not have data yet, this is also an instead of trigger
this wholw block doesn't do anything really, why do you need this trigger?
DELETE FROM Z_MobileSyncFilters WHERE UserID = (SELECT UserID FROM INSERTED);
INSERT INTO Z_MobileSyncFilters
SELECT *
FROM INSERTED;
you second trigger is flawed because it will faile if you have a multi row operation
why do you have 2 insert trigger (1 instead 1 after) on this table?