Trigger not working on Update sql - sql

I wrote a simple stored procedure which is supposed to update an existing table a based on another table b that is continually having values added.
I want the stored procedure to run every time a value is added to b.
I wrote a simple trigger that I think should work but it is not working. The trigger just executes the stored procedure every time there is an insert or update in b.
Here is what the trigger looks like:
CREATE TRIGGER [dbo].[TriggerTest]
ON [dbo].[BELL_DPRA2_locates_fact]
AFTER UPDATE, INSERT
AS
BEGIN
EXECUTE dbo.Test
END
If I run the procedure separately, it works fine. It updates the first table.
But If I leave it waiting for the trigger to act, nothing happens. Table b in the meantime is having data stream in every second. Please help me find the what the problem is.
Here is the stored procedure:
CREATE PROCEDURE [dbo].[Test]
AS
BEGIN
DECLARE #CurDate DATE
SET #CurDate = CAST((SELECT GETDATE()) AS DATE);
MERGE INTO dbo.DPRA2_Export T
USING (SELECT
CAST(risk_date AS DATE) as "Dated",
COUNT(risk_score) AS "Risk2"
FROM
dbo.BELL_DPRA2_locates_fact
WHERE
Risk_Score = 2
AND CAST(Risk_Date AS DATE) = #CurDate
GROUP BY
CAST(risk_date AS DATE)) S ON T.Risk_Date_Day = S.Dated
WHEN MATCHED THEN
UPDATE SET T.Risk2 = S.Risk2
WHEN NOT MATCHED THEN
INSERT (Risk_Date_Day, Risk2)
VALUES (#CurDate, S.Risk2);
END

Related

SQL Insert Trigger - Update other record

I'm working on a small database in SQL Server 2008 to track employee changes. I'm having trouble with an Insert Trigger at the moment. What I want to happen, is that when a "Record" is inserted into the Record table, it finds the previous open record (i.e. one without an end date) for that Employee (EmpID), if there is one, and updates it with an EndDate - which will be calculated as the day before the inserted StartDate. Here is what I have tried, to no success:
CREATE TRIGGER [dbo].[trgInsertRecord] ON [dbo].[Record]
FOR INSERT
AS
declare #EmpID int;
declare #StartDate date;
declare #EndDate date;
select #EmpID=i.EmpID from inserted i;
select #StartDate=i.RealStart from inserted i;
set #EndDate=DATEADD(DAY,-1,#StartDate)
UPDATE Record
SET RealEnd=#EndDate
WHERE EmpID=#EmpID AND RealEnd=NULL;
Can somebody please help me understand my mistake?
Assuming only a single row exists for a given EmpID and NULL RealEnd, you can join to the inserted table for the update operation like the example below. The best practice is to code triggers as to handle multiple rows updated by a single statement so you should avoid local scalar subqueries in triggers.
CREATE TRIGGER [dbo].[trgInsertRecord] ON [dbo].[Record]
FOR INSERT
AS
UPDATE r
SET RealEnd = DATEADD(DAY, -1, i.RealStart)
FROM Record AS r
JOIN inserted AS i ON
r.EmpID=i.EmpID
AND RealEnd IS NULL;

SQL Server trigger won't run the complete update statement?

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.

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

Issue with SQL Server trigger event firing

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!

SQL update trigger

I want a SQL trigger to fire when a table is updated. I have a table called SimActivation and a stored procedure called spUpdateMnpDate that takes two parameters, msisdn(varchar) and date(datetime).
When the SimActivation table is updated I want to call the procedure with the new values.
Here is what I got at the moment, after changing it back and forth:
USE StoreSale;
GO
CREATE TRIGGER dbo.tSyncMnpDate
ON [dbo].[SimActivation]
AFTER UPDATE
AS
DECLARE #date datetime
DECLARE #msisdn varchar(10)
SET #date = (select ProcessDate from inserted)
SET #msisdn = (select Msisdn from inserted)
EXEC [spUpdateMnpDate]
#msisdn, #date;
GO
Can anyone point me in the right direction?
Thanks :)
The problem you have is that a trigger will fire when one or more rows have been updated. At the moment you are assuming your trigger will fire for each row, which is not the case in SQL Server.
If the stored procedure you are trying to call is fairly simple I'd pull the code out of there and in to the trigger. But remember you are working with sets of changed rows (even if the change is to only one row) so you have to write your SQL accordingly.
EDIT: I assume your procedure is updating a date where the PK is equal to #msisdn, if so you can do this in your trigger:
UPDATE Your_Table
SET Your_Table.ProcessDate = inserted.ProcessDate
FROM Your_table INNER JOIN inerted ON Your_Table.Msisdn = inserted.Msisdn
Joining the tables ensures it will work for one or many updated rows.