Using trigger in one table and updating another table - sql

CREATE TRIGGER dbo.updateTrigger
ON dbo.Education
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF NOT (UPDATE( HighestDegreeDoc) OR UPDATE (GPA) OR UPDATE (CreditHours))
RETURN
UPDATE dbo.School
set Uploaded =1
from dbo.School
JOIN inerted i ON i.Uploaded = School.Uploaded
END
GO
What is Wrong with this code. i am trying to update field in School table , field uploaded when (HighestDegreeDoc , GPA, CrediHours) update in Education Table. NOTE Education Table has more than 15 field, (Uploaded Field in School table update only when these 3 field change)

Just a guess....
JOIN inerted i ON i.Uploaded = School.Uploaded
Should be...
JOIN inserted i ON i.SchoolId = School.SchoolId
Looks like Updated is some sort of flag that you are setting. You probably want to join on an ID column instead.

It's only a typo error : it's join inserted ;)
And I don't think your join condition is good.
Can you give us the ddl ?

Related

SQL insert trigger for insert with update

I have two tables:
[1] Donations - with amount and pet_id field
[2] Pets - with id and total donations field
I'm trying to create a trigger which will update total donations field whenever
a new row is being inserted to Donations table. I tried this one:
create trigger update_donations
on sponserships
for insert
as
update dbo.Pets
set tot_donations = (
select new_val = inserted.amount + pets.tot_donations
from inserted
where inserted.[Pet-ID] = pets.[Animal-ID]
)
But of course it changes all records, whereas i want to change only records that are changed in the donations table.
It is usually not a good practice to store this type of derived information - you could have a view that computes it on the fly rather than a trigger that keeps it up to date. Also please note that if you go that way, you also need a delete and an update trigger...
That said, you can use the following query in your insert trigger to update the relevant record in the pets table:
update p
set p.total_donations = p.total_donations + i.amount
from dbo.Pets p
inner join inserted i on i.[Pet-ID] = p.[Animal-ID]

SQL After trigger update value that triggers update

I have 2 tables, shipment and invoice. I have an after trigger that updates the shipment table with the invoice number from the invoice table.The invoice table has their related shipment numbers, can be more than one for each invoice.
Create Trigger ShipmentInvoice
on Therefore.dbo.Invoice
For Insert
AS
Update cat set
invoice = Fac.invoice
FROM therefore.dbo.thecat10 cat
INNER JOIN therefore.dbo.vFacturaAlbaran alb
on alb.shipment COLLATE Modern_Spanish_CI_AS = alb.shipment
This Works but it updates the whole table every time. I need a way to update the shipment table only with the values that were recently added in the invoice table when the trigger is activated.
Edit
The trigger is over the invoice table. I am updating the shipment table with the invoice numbers from the invoice table.
This Works but it updates the whole table every time. I need a way to update the shipment table only with the values that were recently added in the invoice table when the trigger is activated.
That because you are joining both tables, you need to use INSERTED table to get only the inserted rows as :
Create Trigger ShipmentInvoice
on Therefore.dbo.Invoice
For Insert
AS
Update cat set
invoice = I.invoice
FROM therefore.dbo.thecat10 cat
INNER JOIN INSERTED I alb ON Cat.ID = I.ID
...
it seems odd that you are updating the table to you are already inserting into; why are you not resolving the correct value before hand? This is pseudo-sql, but will get you on the right path
CREATE TRIGGER ShipmentInvoice
ON Therefore.dbo.Invoice
FOR INSERT
AS
UPDATE cat
SET invoice = Fac.invoice --There is no table/alias Fac, where is this coming from? inserted?
FROM therefore.dbo.thecat10 cat
JOIN inserted i ON cat.{Primary/Foreign ID COLUMN} = i.{Primary/Foreign ID COLUMN}
INNER JOIN therefore.dbo.vFacturaAlbaran alb ON alb.shipment COLLATE Modern_Spanish_CI_AS = alb.shipment;
Note the items in the braces ({}) and also my comment about your object Fac.

How to use the original value in a SQL Server update trigger to change a second record

I have a SQL Server table with student, cohort, program, grad date, and status. Some students have records that are specifically tied together – if the cohort for one row changes, the cohort for another row with status 2 needs to change as well. In most cases I catch this programmatically but there are a LOT of ways to change a student’s cohort so we’re missing some.
Essentially if someone runs the first line update statement, the second also needs to run
UPDATE StudentPrograms
SET Cohort = 201610
WHERE Student = 'A1234' AND Program = 'MBA' AND Cohort = 201510
UPDATE StudentPrograms
SET Cohort = 201610
WHERE Student = 'A1234' AND Cohort = 201510 AND Status = 2
I would like to put an update trigger on the table to change both cohorts, but the problem is I can’t figure out how to capture both the starting cohort that identifies the record that needs to change and the cohort that it would need to change to. Once the update has run and the trigger fires, all I have is the updated cohort, so I don’t know which record to change.
CREATE TRIGGER [dbo].[tr_SP_Cohort]
ON [dbo].StudentPrograms
AFTER UPDATE
AS
DECLARE #student VARCHAR(10);
DECLARE #cohort INT;
SELECT #student = i.student FROM inserted i
SELECT #cohort = i.cohort FROM inserted i
SET NOCOUNT ON;
IF UPDATE(Cohort)
UPDATE dbo.StudentPrograms
SET Cohort = #cohort
WHERE Student = #student AND Status = 2 AND Cohort = ???
Unfortunately the records do have to be in this table and not a sub table for a lot of reasons. The records are occasionally also deleted / reinserted, so I run into the same problems if I tie them together by adding another field with a key - if that record gets deleted / updated / reinserted, I still need to capture the information, record it, then record the change.
Thanks for the immediate help! Here's what I ended up with, changed a bit so it works with batch updates.
ALTER TRIGGER [dbo].[tr_SP_Cohort]
ON [dbo].StudentPrograms
AFTER UPDATE
AS
SET NOCOUNT ON;
IF UPDATE(Cohort)
UPDATE a
SET Cohort = i.Cohort
FROM dbo.StudentPrograms AS a
INNER JOIN inserted AS i ON a.Student = i.Student
INNER JOIN deleted AS d ON a.Cohort = d.Cohort
AND a.Student = d.Student
WHERE a.Status = 2
When creating a trigger, you can access the old values using the deleted table
WHERE Student = #student AND Status = 2 AND Cohort = (SELECT TOP 1 Cohort from deleted)
Ideally, you should handle this in a stored procedure but as a temporary fix you can use the following code.
They way you are handling updates in your code, it will never work if more than one row was updated.
Triggers are fired once in response to a triggering action (update,delete,insert) for all the rows affected by that action, NOT for each row affected by the triggering action.
Keeping all this in mind your temporary solution should look something like...
CREATE TRIGGER [dbo].[tr_SP_Cohort]
ON [dbo].StudentPrograms
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE s
SET s.Cohort = i.Cohort
FROM deleted d
INNER JOIN dbo.StudentPrograms s ON d.Student = s.Student
AND d.Cohort = s.Cohort
INNER JOIN inserted i ON i.Student = s.Student
WHERE s.[Status] = 2;
END

Database trigger to update a row on parent table after child table has been updated

First time creating a Database trigger. I have a child table that when its cost column is updated, I need its parent table to also update its cost column to reflect the change.
Here is my sorry attempt so far. That's obviously not working. I am having a problem figuring out how to extract the total cost as a variable and store it in the parent table.
My current approach assumes a static id vaule at the moment. I am not entirely sure how to dynamically determine the id value of the row that was updated.
CREATE TRIGGER ParentCost_Update
ON ChildTable
AFTER INSERT, UPDATE
AS
SELECT SUM(Cost) AS TotalCost FROM ChildTable where parent_id=2080
UPDATE ParentTable
SET Cost=TotalCost
where id=parent_id;
GO
This current script is returning an error
Msg 207, Level 16, State 1, Procedure ParentCost_Update, Line 9
Invalid column name 'TotalCost'.
You need to be careful in triggers, in that there could be more than one row updated. Therefore, you need to do row-based handling.
To obtain the newly inserted / updated row, use the inserted and deleted pseudo rows.
You will almost certainly also going to need to implement a deleted trigger as well, viz, if a row is removed from a child table that the parent will need to be recalculated.
Here's a row based take, using a CTE to map your two-step process above , as follows:
CREATE TRIGGER ParentCost_Update
ON ChildTable
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
WITH cteParentsAffected AS
(
SELECT ins.parent_id
FROM inserted ins
UNION
SELECT del.parent_id
FROM deleted del
)
, cteTotal AS
(
SELECT ct.parent_id, SUM(ct.Cost) AS TotalCost
FROM ChildTable ct
INNER JOIN cteParentsAffected par
ON ct.parent_id = par.parent_id
GROUP BY ct.parent_id
)
UPDATE pt
SET Cost=cte.TotalCost
FROM ParentTable pt
INNER JOIN cteTotal cte
ON id=cte.parent_id;
GO
With a SqlFiddle here
Try this
Update parenttable set total= (select sum(total) from childtable c where c.id= parent table.id)
Where id in (select id from inserted)
Change the table and column names.

SQL trigger with parsing and existence check on another table

So I have a work order table with 3 fields relevant to the question being asked here
(dbo.workorder with some sample values):
location | supervisor | ownergroup
ABC-123 | JSMITH | ALPHA
XYZ-987 | JDOE | OMEGA
ABC-123 | NULL | NULL
XYZ-987 | NULL | NULL
The last two rows are to show that sometimes the supervisor/ownergroup is not filled out when inserting a workorder row which leads to the question! I have another table called "roles" with rows such as below:
role | value
ABCSupervisor | JSMITH
ABCOwnergroup | ALPHA
XYZSupervisor | JDOE
XYZOwnergroup | OMEGA
As you can see from the "roles" table, a role is made up of the first 3 letters of the location (ALWAYS) plus the word Supervisor or Ownergroup. When the 3rd and 4th rows of the "workorder" table are inserted, I'd like to develop a trigger that would attempt to fill in the values for Supervisor/Ownergroup IF there is a match in the "roles" table. If there isn't a supervisor/ownergroup for that location prefix, then it should default to a set value (let's say supervisor='super' and ownergroup='og'). Here's what I have so far, though perhaps a different approach would be better:
CREATE TRIGGER [dbo].[OwnergroupSupervisor]
ON [dbo].[workorder]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE wo
SET wo.ownergroup= (THIS IS WHERE I NEED HELP)
FROM dbo.workorder AS wo INNER JOIN inserted AS i ON wo.wonum=i.wonum
WHERE wo.ownergroup IS NULL
END
GO
I'm guessing an IF EXISTS or a CASE of some sort? Probably involving something like LEFT(wo.location,3)+'Ownergroup' perhaps?
Any and all help is greatly appreciated! Thanks!
Clarification:
wonum is the primary key for the "workorder" table. I am joining the "inserted" table (which contains the rows that are being inserted or updated) to the "workorder" table so that I am only updating the new/updated rows and not the entire "workorder" table. Nothing in my question right now has anything to do with the "roles" table. See update 1 below for a better understanding of what I'm doing...
Update 1:
I've worked out one solution, but if there is nothing in the "roles" table, it just leaves the supervisor/ownergroup null instead of changing it to a default value. I can deal with this for now, but would like a better option. Here's what I have:
CREATE TRIGGER [dbo].[OwnergroupSupervisor]
ON [dbo].[workorder]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE wo
SET wo.ownergroup=(SELECT value FROM roles WHERE role=LEFT(wo.location,3)+'Ownergroup')
FROM dbo.workorder AS wo INNER JOIN inserted AS i ON wo.wonum=i.wonum
WHERE wo.ownergroup IS NULL
UPDATE wo
SET wo.supervisor=(SELECT value FROM roles WHERE role=LEFT(wo.location,3)+'Supervisor')
FROM dbo.workorder AS wo INNER JOIN inserted AS i ON wo.wonum=i.wonum
WHERE wo.supervisor IS NULL
END
I have not worked out what would happen if two rows were found in the roles table (although I'm pretty sure the application restricts this so it should be OK). But as I mentioned above, this just keeps the supervisor/ownergroup NULL if no role is found in the roles table.
How you can update the workorder table based on information in roles is as below:
update wo
set ownergroup = isnull(r.value, 'og')
from workorder wo
left outer join roles r on r.role = left(wo.location, 3) + 'Ownergroup'
where wo.ownergroup is null
Then you can do a similar update for the Supervisor role.
In theory, the full answer is something like:
create trigger [dbo].[ownergroupsupervisor]
on [dbo].[workorder]
after insert,update
as
begin
set nocount on;
update wo
set wo.ownergroup= isnull(r.value, 'og')
from dbo.workorder as wo
inner join inserted as i on wo.wonum=i.wonum
left outer join roles r on r.role = left(wo.location, 3) + 'Ownergroup'
where wo.ownergroup is null
-- Repeat for Supervisor
end
go
I'm not sure what column wonum is (though I assume it's the work order #), and if it joins them, but if it does you look like you want to update your ownergroup with the value column from the roles table
CREATE TRIGGER [dbo].[OwnergroupSupervisor]
ON [dbo].[workorder]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE wo
SET wo.ownergroup= r.value
FROM
dbo.workorder AS wo
INNER JOIN
inserted AS i ON wo.wonum=i.wonum
join
roles r
on left(wo.location,3) + 'Ownergroup'=r.role
WHERE
wo.ownergroup IS NULL
END
GO
If i'm misunderstanding what you want please let me know.