How to update a single table using trigger in MS SQL 2008 - sql

I have a table PeroidicDeduction and the fields are ID(auto-increment),TotalDeduction(e.g.it can be loan),Paid(on which the deduction for each month),RemainingAmount,
What I want is when every time I insert or update the table---RemainingAmount will get the value of TotalDeduction-SUM(Paid)....and writ the following trigger...but dosen't work for me
CREATE TRIGGER dbo.UpdatePD
ON PeroidicDedcution
AFTER INSERT,UPDATE
AS
BEGIN
UPDATE PeroidicDedcution
SET REmaininAmoubnt=(SELECT TotalDeduction-(SELECT SUM(Paid) FROM PeroidicDeduction) FROM PeroidicDeduction)
END
NOTE: it is on a Single table

Create two triggers, an INSTEAD OF UPDATE and INSTEAD OF INSERT. Here is the code for the INSTEAD OF UPDATE:
CREATE TRIGGER dbo.UpdatePD ON PeroidicDedcution
INSTEAD OF Update
AS
SET NOCOUNT ON
UPDATE p
SET col1=i.col1
,col2=i.col2
FROM INSERTED i
INNER JOIN PeroidicDedcution p ON i.PK=p.PK
UPDATE PeroidicDedcution
SET REmaininAmoubnt=(SELECT TotalDeduction-(SELECT SUM(Paid) FROM PeroidicDeduction) FROM PeroidicDeduction)
go
It will do both the original update that fires the trigger, as well as the SUM logic from the trigger in the question.
here is the INSTEAD OF INSERT trigger:
CREATE TRIGGER dbo.InsertPD ON PeroidicDedcution
INSTEAD OF INSERT
AS
SET NOCOUNT ON
INSERT INTO PeroidicDedcution
(col1, col2, ...)
SELECT
col1, col2, ...
FROM INSERTED
UPDATE PeroidicDedcution
SET REmaininAmoubnt=(SELECT TotalDeduction-(SELECT SUM(Paid) FROM PeroidicDeduction) FROM PeroidicDeduction)
go

You should not use a trigger to do this as it will recursively fire itself if you have an update trigger on a table and the trigger causes and update to the same table. rather add the logic to your insert and update stored procedures

Related

Trigger works based on type of insert SQL Server

I am working in SQL Server Management Studio v18, and I have the following trigger:
CREATE TRIGGER [dbo].[update_surface]
ON [dbo].[my_table]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #surface_m2 REAL
SET #surface_m2 = (SELECT cast(round(CAST(Dimension1*Dimension2 as decimal)/ cast(1000000 as decimal),3,3) as decimal(10,3)) AS surface FROM my_table WHERE Surface_m2 IS NULL)
UPDATE dbo.my_table SET Surface_m2 = #surface_m2
END
I have two columns in my_table, which are Dimesion1 and Dimension2. I want that the trigger multiplies them, and set the result to other column in the same table, which is Surface_m2, whenever this column is null. The trigger does his function, but based on the type of insert I do:
If I insert a row in my_table by the graphic environment the trigger works as I wish. With each new row, Surface_m2 has his own result.
But if I insert by INSERT INTO my_table VALUES ().... (query) the trigger updates Surface_m2 column of all previous rows with the result of each new insert.
Why is the trigger working like that? Is there any other simple way to do what I am trying to do?
Thanks.
Insert trigger gives you actual values that are inserted in a special table called... "inserted".
So what you need to do is join this table against your main table and perform the logic needed, no variables required.
Something like this untested code
create trigger...
begin
UPDATE t
SET Surface_m2 = cast(round(CAST(t.Dimension1*t.Dimension2 as decimal)
/ cast(1000000 as decimal),3,3) as decimal(10,3))
from dbo.my_table t
inner join inserted i
ON i.ID = t.ID
WHERE t.Surface_m2 IS NULL
end
This begs the question though, why can't you just insert the Surface_m2 value yourself. Or even better, change Surface_m2 to be a computed column if it's always depends on Dimension1 and Dimension2

Trigger preventing a column from being updated

I have created a trigger as below:
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- update statements for trigger here
declare #id1 int, #matchFK int;
select #id1 = i.id from inserted i;
select #matchFK=i.AT_MatchFk from inserted i;
update dbo.AT_LastViewedMatch set matchId = #matchFK where id = #id1;
END
GO
While this trigger works- I am not able to update the value of the matchId column directly from SQLManager:
If I execute
UPDATE AT_LastViewedMatch set matchId='1179619' where id=5762
for example, I am still seeing the old value for matchId. I think the issue is related to the above trigger (since if I drop the trigger, it works). Is there a way to get past this?
From your trigger definition below, you have created it for insert and update
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT,UPDATE <-- Here
so essentially, whenever you are running an update statement from SSMS
UPDATE AT_LastViewedMatch set matchId='1179619' where id=5762
Your trigger performing the below line and setting it to old value
update dbo.AT_LastViewedMatch set matchId = #matchFK where id = #id1;
You need to remove that update from your trigger definition
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT

Deleted Virtual table in SQL Server is empty ON Delete trigger

I am trying to invoke an ON Delete trigger event, but when I try to select row from the Deleted table, it is empty.
Is there any other way to get Id of row on which delete event has fired?
Code:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER TRIGGER [audit]
ON [dbo].[S_PARTY]
FOR DELETE
AS
-- Insert statements for trigger here
DECLARE #id nvarchar(50)
SET #id = (Select ROW_ID from deleted )
BEGIN
-- Insert statements for trigger here
INSERT INTO [dbo].[S_AMF_AUDIT_ITEM] (ROW_ID)
VALUES (#id);
END
When trigger fires on this, I am getting error as S_AMF_AUDIT_ITEM doesn't allow null values. So can you please help me this to get Id of table on which delete command executes?
Your trigger is broken.
It doesn't take into account that the DELETE statement might affect zero or more than one rows.
The issue with NULL could occur for the statement DELETE FROM [dbo].[S_PARTY] WHERE 1 = 0.
A fixed version would be
ALTER TRIGGER [audit]
ON [dbo].[S_PARTY]
FOR DELETE
AS
BEGIN
INSERT INTO [dbo].[S_AMF_AUDIT_ITEM]
(ROW_ID)
SELECT ROW_ID
FROM deleted;
END
A trigger can fire for 0..N deleted rows. For example:
delete YourTable
where 1=2
Would run a for delete trigger on YourTable. So a trigger has to be able to deal with zero or multiple rows. Consider rewriting your trigger like:
ALTER TRIGGER [audit] ON [dbo].[S_PARTY] FOR DELETE
AS
INSERT dbo.S_AMF_AUDIT_ITEM
(ROW_ID)
SELECT ROW_ID
FROM deleted
That will work for any number of inserted rows.

SQL Server 2008 created/last updated trigger issue

I am using this trigger in order to fill in the CreatedDate and LastUpdated columns (of type datetime) in a table:
CREATE TRIGGER trCreatedDate ON [LasMTest]
FOR INSERT
AS
UPDATE [LasMTest]
SET [LasMTest].Created = getdate(),
[LasMTest].LastModified = getdate()
FROM [LasMTest]
INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID]
GO
When I check the table, the dates are off by just a fraction of a second.
Created LastModified ID
2013-03-19 09:24:32.920 2013-03-19 09:24:32.930 4
2013-03-19 09:26:39.890 2013-03-19 09:26:39.900 5
How can I modify the trigger so that they are both the exact time?
It's the interaction of your two triggers that's causing the problem.
If, instead, you set both columns to default to getdate() and ditch your insert trigger, it should work - the INSERT won't also cause an UPDATE.
The alternative is to author your INSERT trigger as an INSTEAD OF trigger that performs an INSERT rather than an UPDATE (and thus, also, avoids the UPDATE trigger firing).
If you do want to write it as an INSTEAD OF trigger, it would be something like:
CREATE TRIGGER trCreatedDate ON [LasMTest]
INSTEAD OF INSERT
AS
INSERT INTO LasMTest (/* Column List */,Created,LastModified)
SELECT /* Column List */,getdate(),getdate() from inserted
GO
INSERTs into the triggering table in an INSTEAD OF trigger don't (thankfully) cause the trigger to be fired recursively. If ID is an IDENTITY column, then it should appear in the column lists above (it hasn't been generated yet).
Try this:
CREATE TRIGGER trCreatedDate ON [LasMTest]
FOR INSERT
AS
Declare #CurrentDate Datetime
Set #CurrentDate=getdate()
UPDATE [LasMTest] SET [LasMTest].Created=#CurrentDate,[LasMTest].LastModified=#CurrentDate
FROM [LasMTest] INNER JOIN Inserted ON [LasMTest].[ID]= Inserted.[ID]
GO
You basically want to avoid the UPDATE trigger when doing the update from INSERT. This is called Nested Triggers. One easy solution is to use CONTEXT_INFO() to communicate to the nested UPDATE trigger code that you are already in an INSERT trigger so it suppresses itself:
CREATE TRIGGER trCreatedDate ON [LasMTest]
FOR INSERT
AS
SET CONTEXT_INFO 0xDEADBEEF;
UPDATE [LasMTest]
SET [LasMTest].Created = getdate(),
[LasMTest].LastModified = getdate()
FROM [LasMTest]
INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID];
SET CONTEXT_INFO NULL;
GO
CREATE TRIGGER trModifiedDate ON [LasMTest]
FOR UPDATE
AS
DECLARE #context varbinary(128);
SET #context = CONTEXT_INFO();
IF #context is NULL
BEGIN
UPDATE [LasMTest]
SET [LasMTest].LastModified = getdate()
FROM [LasMTest]
INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID];
END
GO
However such an approach is fragile. An exception can leave the context_info set and suppress all subsequent UPDATE triggers in the session. This requires adding TRY/CATCH blocks. And you always run the risk of an application using CONTEXT_INFO for its own purposes and ruining your scheme.
Another solution is to make the UPDATE trigger smart. It can check the UPDATE(Created) inside the UPDATE trigger and suppress any action if the Created column was modified. This works by convention, because you know that the only place that updates the Created column is the INSERT trigger:
CREATE TRIGGER trModifiedDate ON [LasMTest]
FOR UPDATE
AS
IF NOT UPDATE(Created)
BEGIN
UPDATE [LasMTest]
SET [LasMTest].LastModified = getdate()
FROM [LasMTest]
INNER JOIN Inserted ON [LasMTest].[ID] = Inserted.[ID];
END
GO

After insert, update trigger not running

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?