This is my Trigger. The first two UPDATE Statements work but, the UPDATE Student does not work.
"UPDATE Student SET PointsAccumulated = PointsAccumulated + #Points
Where #StudentID = StudentID"
CREATE TRIGGER [Trigger]
ON [dbo].[Attendance]
After insert
AS
BEGIN
DECLARE #EventID int
Declare #StudentID nchar
DECLARE #Points int
SELECT #EventID=EventID from inserted
SELECT #EventID = EventID, #Points = Points from Event
SELECT #StudentID = StudentID from inserted
Update Event SET Attendance = Attendance + 1
WHERE #EventID = EventID
UPDATE Attendance SET Points = #Points
Where #EventID = EventID
UPDATE Student SET PointsAccumulated = PointsAccumulated + #Points
Where #StudentID = StudentID
THE SOLUTION that worked for me from HLGEM :
Update E
SET Attendance = Attendance + 1
FROM Event E
JOIN Inserted I ON i.eventid = e.eventid
UPDATE A
SET Points = e.points
FROM Attendance a
JOIN Event E ON a.EventID = e.EventID
JOIN Inserted I ON i.EventID = e.EventID
UPDATE S
SET PointsAccumulated = PointsAccumulated + e.points
FROM Student S
JOIN Inserted I ON i.studentID = s.studentID
JOIN Event E ON i.eventid = e.eventid
Lessons Learned:
In SQL Server, it is never appropriate to use a variable (other than a table variable) to grab what was changed in the table in a trigger as they do not work row-by row like triggers in some other databases
--HLGEM
This is not tested, but I think this is what you need:
CREATE TRIGGER [Trigger]
ON [dbo].[Attendance]
After insert
AS
BEGIN
Update E
SET Attendance = Attendance + 1
FROM Event E
JOIN Inserted I ON i.eventid = e.eventid
UPDATE A
SET Points = e.points
FROM Attendance a
JOIN Event E ON a.eventid = e.eventid
JOIN Inserted I ON i.eventid = e.eventid
UPDATE S
SET PointsAccumulated = PointsAccumulated + e.points
FROM Students s
JOIN Inserted I ON i.StudentID = e.StudentID
JOIN Event E ON i.eventid = e.eventid
Note that this fixes the incorrect first two updates as well. When writing SQL Server trigger, you must assume there will be more than one record in inserted or deleted. Further, you need to test the trigger by deliberately making sure that multiple records were affected by the initial insert or update. It is irresponsible to create a trigger with the assumption that only one record at a time will ever be inserted, updated or deleted. ANd if you don;t test for the behavior like that, you will have a trigger that creates a data integrity disaster as almost all tables eventually have a multiple record insert/update or deletion.
I think you should take a deep look:
First: You're assigning twice #EventID, from inserted and from Event table
SELECT #EventID=EventID from inserted
SELECT #EventID = EventID, #Points = Points from Event
Second: I suppose you would use some key reading the Event table
SELECT #Points = Points from Event "WHERE EventID = #EventID"
Then, #Points maybe has no value due this last sentence has not read anything.
Related
I'm need to run a calculation for month every day. If the month period, exists already, I need to update it, else I need to create a new row for the new month.
Currently, I've written
declare #period varchar(4) = '0218'
DECLARE #Timestamp date = GetDate()
IF EXISTS(select * from #output where period=#period)
/* UPDATE #output SET --- same calculation as below ---*/
ELSE
SELECT
#period AS period,
SUM(timecard.tworkdol) AS dol_local,
SUM(timecard.tworkdol/currates.cdrate) AS dol_USD,
SUM(timecard.tworkhrs) AS hrs,
#Timestamp AS timestamp
FROM dbo.timecard AS timecard
INNER JOIN dbo.timekeep ON timecard.ttk = timekeep.tkinit
INNER JOIN dbo.matter with (nolock) on timecard.tmatter = matter.mmatter
LEFT JOIN dbo.currates with (nolock) on matter.mcurrency = currates.curcode
AND currates.trtype = 'A'
AND timecard.tworkdt BETWEEN currates.cddate1
AND currates.cddate2
WHERE timekeep.tkloc IN('06','07') AND
timecard.twoper = #period
SELECT * FROM #output;
How can simply update my row with the new data from my select.
Not sure what RDBMS are you using, but in SQL Server something like this would update the #output table with the results of the SELECT that you placed in the ELSE part:
UPDATE o
SET o.dol_local = SUM(timecard.tworkdol),
SET o.dol_USD = SUM(timecard.tworkdol/currates.cdrate),
SET o.hrs = SUM(timecard.tworkhrs),
set o.timestamp = #Timestamp
FROM #output o
INNER JOIN dbo.timecard AS timecard ON o.period = timecard.twoper
INNER JOIN dbo.timekeep ON timecard.ttk = timekeep.tkinit
INNER JOIN dbo.matter with (nolock) on timecard.tmatter = matter.mmatter
LEFT JOIN dbo.currates with (nolock) on matter.mcurrency = currates.curcode
AND currates.trtype = 'A'
AND timecard.tworkdt BETWEEN currates.cddate1
AND currates.cddate2
WHERE timekeep.tkloc IN('06','07') AND
timecard.twoper = #period
Also, I think you want to do an INSERT in the ELSE part, but you are doing just a SELECT, so I guess you should fix that too
The answer to this will vary by SQL dialect, but the two main approaches are:
1. Upsert (if your DBMS supports it), for example using a MERGE statement in SQL Server.
2. Base your SQL on an IF:
IF NOT EXISTS (criteria for dupes)
INSERT INTO (logic to insert)
ELSE
UPDATE (logic to update)
I have a stored procedure which runs and inserts into 10 separate tables. On the very first table I have an "After insert" trigger. However the stored procedure is wrapped in a transaction and is only committed once it has inserted into all 10 tables.
My question is would my trigger only fire once the stored procedure has been committed? Currently I am experiencing issues whereby the record is inserted via asp.net application fine, but the trigger has not fired (the trigger just captures what row was inserted)
ALTER TRIGGER [dbo].[trProductAllergenUpdate]
ON [dbo].[ProductAllergen]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO AUDIT_PRODUCT (ProductID, Portal_Table, Portal_Column, AuditDescription, UpdateDateTime, OldValue, NewValue)
SELECT
I.ProductID, 'ProductAllergen', 'AllergenStatusID',
'Allergen - ' + AT.AllergenType, Getdate(),
AS2.AllergenStatus, AS1.AllergenStatus
FROM
Inserted I
INNER JOIN
(SELECT PA2.*
FROM ProductAllergen PA2
INNER JOIN
(SELECT
ProductID, AllergenTypeID, MAX(productAllergenID) [ProductAllergenID]
FROM ProductAllergen
WHERE isLive = 0
GROUP BY ProductID, AllergenTypeID) X ON PA2.ProductAllergenID = X.ProductAllergenID
) OLD ON OLD.ProductID = I.ProductID
AND OLD.AllergenTypeID = I.AllergenTypeID
INNER JOIN
ProductAllergen NEW ON NEW.ProductID = OLD.ProductID
AND NEW.AllergenTypeID = OLD.AllergenTypeID
INNER JOIN
AllergenType AT ON I.AllergenTypeID = AT.AllergenTypeID
INNER JOIN
AllergenStatus AS1 ON NEW.AllergenStatusID = AS1.AllergenStatusID
INNER JOIN
AllergenStatus AS2 ON OLD.AllergenStatusID = AS2.AllergenStatusID
WHERE
New.isLive = 1
AND OLD.AllergenStatusID <> NEW.AllergenStatusID
END
I've written a trigger that must update CCCMPMTRL table when the column PRICER01 from MTRL table updates. The primary key from the table MTRL is also a column named MTRL which I also keep in the table that must update (CCCMPMTRL) as a foreign key. The thing is that whenever I update the MTRL table, in the CCCMPMTRL, values update for all the records I have in MTRL, but I want for one only, the current one. What do I do wrong?
Code looks like this:
CREATE TRIGGER dbo.[test_Price]
ON dbo.[MTRL]
AFTER UPDATE
AS
DECLARE #MTRL INT;
DECLARE #OLDPRICER01 FLOAT(2);
DECLARE #NEWPRICER01 FLOAT(2);
DECLARE #MPMTRL INT;
SET #MTRL = (SELECT I.MTRL FROM INSERTED I,MTRL M WHERE M.MTRL = I.MTRL);
SET #MPMTRL = (SELECT MTRL FROM MTRL WHERE MTRL=#MTRL);
SET #OLDPRICER01 = (SELECT PRICER01 FROM MTRL WHERE MTRL =#MTRL AND SODTYPE = 51)
SET #NEWPRICER01 = (SELECT PRICER01 FROM INSERTED WHERE MTRL = #MTRL AND SODTYPE = 51)
IF(NOT EXISTS(SELECT CM.MTRL FROM CCCMPMTRL CM, INSERTED I WHERE CM.MTRL = I.MTRL))
INSERT INTO CCCMPMTRL
SELECT M.MTRL,D.PRICER01,I.PRICER01 FROM INSERTED I, DELETED D, MTRL M WHERE I.MTRL = #MTRL
ELSE
IF(#OLDPRICER01 <> #NEWPRICER01)
UPDATE CCCMPMTRL
SET OLDPRICER01 = #OLDPRICER01,
NEWPRICER01 = #NEWPRICER01
FROM CCCMPMTRL AS CM
WHERE CM.MTRL = #MTRL
Try this
UPDATE CM
SET OLDPRICER01 = D.PRICER01,
NEWPRICER01 = I.PRICER01
FROM INSERTED I
JOIN DELETED D ON D.MTRL=I.MTRL
JOIN CCCMPMTRL CM ON CM.MTRL=I.MTRL
WHERE D.PRICER01 <> I.PRICER01
INSERT INTO CCCMPMTRL
SELECT I.MTRL, D.PRICER01, I.PRICER01
FROM INSERTED I
JOIN DELETED D ON D.MTRL=I.MTRL
LEFT JOIN CCCMPMTRL C ON C.MTRL=I.MTRL
WHERE C.MTRL IS NULL
Because the UPDATE statement uses an inner join on CCMPMTRL it will only update where a row already exists, whereas the INSERT statement uses a left outer join to exclude existing values of MTRL.
This should work whether you are inserting one or many rows at once, and there is no need for all those local variables.
Kindly help, I have been trying to create an update trigger to insert data into a specific table once it's updated with a certain value. "Accepted". for somewhat reason the trigger is not firing
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[TRGIU_CLEARING_SAMPLE_RESULT]') and OBJECTPROPERTY(id, N'IsTrigger') = 1)
DROP TRIGGER [dbo].[TRGIU_CLEARING_SAMPLE_RESULT]
GO
CREATE TRIGGER [dbo].[TRGIU_CLEARING_SAMPLE_RESULT] ON [dbo].[CLEARING_BATCH]
AFTER INSERT
AS
IF UPDATE(QM_STATUS)
BEGIN
Declare #QM_Status Varchar(12),
#QM_Status_Old Varchar(12),
#Submission_Pk Uniqueidentifier
SELECT #QM_Status = I.QM_STATUS,
#QM_Status_old = D.QM_STATUS,
#Submission_Pk = I.PK
--#Lab_used = LE.ID
FROM CLEARING_BATCH CB
LEFT JOIN SAMPLE_RESULT SR ON CB.PK = SR.PPK
JOIN INSERTED I ON SR.PK = I.PPK
JOIN DELETED D ON I.PK = D.PK
IF(#QM_Status = 'Accepted' and (#QM_Status <> #QM_Status_old or #QM_Status_old is null))
begin
INSERT INTO BATCH(PPK,BATCH_ID)
SELECT CB.PK,CB.BATCH_ID
FROM LABORATORY L
JOIN CLEARING_BATCH CB ON L.PK = CB.PPK
JOIN CLEARING_SAMPLE_RESULT CSR ON CB.PK = CSR.PPK
LEFT JOIN BATCH B ON CB.PK = B.PPK
WHERE B.PPK IS NULL
UPDATE BATCH
SET BATCH_ID = CB.BATCH_ID
FROM BATCH B
JOIN CLEARING_BATCH CB ON B.PPK = CB.PPK
END
end
GO
You have an AFTER INSERT trigger
CREATE TRIGGER [dbo].[TRGIU_CLEARING_SAMPLE_RESULT]
ON [dbo].[CLEARING_BATCH]
AFTER INSERT
AS
which will fire after any INSERT statement that inserts new rows - this will NOT be fired when you UPDATE something!
If you want to capture the UPDATE operations, you need an AFTER UPDATE trigger instead:
CREATE TRIGGER [dbo].[TRGIU_CLEARING_SAMPLE_RESULT]
ON [dbo].[CLEARING_BATCH]
AFTER UPDATE
AS
....
I have the following trigger is causing me grief.
ALTER TRIGGER [dbo].[T_DMS_Factory_I]
ON [dbo].[jobrun]
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
IF NOT EXISTS (select * from inserted i
inner join [db2].[dbo].[table2] t2 on t2.JobRunID = i.jobrun_id)
UPDATE [db2].[dbo].[table2]
SET ProdDt = i.jobrun_proddt,
CreateDt = GETDATE(),
JobrunID = i.jobrun_id,
Start = i.jobrun_time,
End = i.jobrun_stachgtm,
Status = i.jobrun_status,
ActiveDuration = i.jobrun_duration,
TotalDuration = i.jobrun_duration
FROM inserted i
INNER JOIN jobmst jm ON jm.jobmst_id = i.jobmst_id
WHERE jm.jobmst_alias = 'blah'
END
The above works fine but it updates ALL the rows with the same data which I don't want. I only want it to update the row where the time is after before the time of the insert from another column called baseEnd
WHERE jm.jobmst_alias = 'blah' AND baseEnd <= i.jobrun_time AND JobRunID IS NOT NULL
That is what I'd imagine should work but it isn't. What am I doing wrong?
Looking at the tables in your code
UPDATE [db2].[dbo].[table2]
SET
....
FROM inserted i
inner join jobmst jm on jm.jobmst_id = i.jobmst_id
where jm.jobmst_alias = 'blah'
shouldn't you have table2 in the FROM Clause if you're going to update matching records in it.
Otherwise you're just getting some records back from the inserted and jobmst tables and firing values from one of them into all the records in table2
That's why it's not working anyway
It's difficult to see quite what the logic you're trying to implement is but this might be what you need
UPDATE t2
SET ProdDt = i.jobrun_proddt,
CreateDt = GETDATE(),
JobrunID = i.jobrun_id,
Start = i.jobrun_time,
End = i.jobrun_stachgtm,
Status = i.jobrun_status,
ActiveDuration = i.jobrun_duration,
TotalDuration = i.jobrun_duration
FROM inserted i
inner join jobmst jm on jm.jobmst_id = i.jobmst_id
inner join [db2].[dbo].[table2] t2 ON t2.baseEnd <= i.jobrun_time
where jm.jobmst_alias = 'blah'