Trigger Update another table After Insert - sql

I have 2 tables Employee and Employee_Backup
Employee has 3 columns
IDEmployee
Name
Status
and Employee_Backup also has 3 columns:
IDEmployee
Detail
Status
For every row inserted into or updated in table Employee, I want to set the Status in table Employee_Backup using this criteria
WHERE employee_backup.IDEmployee = employee.IDEmployee (inserted / updated)

Something like that??
CREATE TRIGGER tr_Employee_Insert
ON dbo.Employee
FOR INSERT
AS
UPDATE b
SET Status = 'Inserted'
FROM dbo.Employee_Backup b
INNER JOIN Inserted i ON b.EmployeeID = i.EmployeeID
CREATE TRIGGER tr_Employee_Update
ON dbo.Employee
FOR UPDATE
AS
UPDATE b
SET Status = 'Updated'
FROM dbo.Employee_Backup b
INNER JOIN Inserted i ON b.EmployeeID = i.EmployeeID
You basically need to join the Inserted pseudo table which contains all rows that have been inserted (or updated) from the base table (dbo.Employee) and the Employee_Backup table - and then use that result set from the JOIN as the basis for your UPDATE statement.
Note: this will NOT insert any new rows into Employee_Backup when you add new rows to dbo.Employee - is that what you want? If not, you'd have to change the FOR INSERT trigger a bit ....

Related

How to write a sql update query for below condition?

I have 2 tables. First is employee table and has (id,emp_num,name,address_id,text) columns.
Second is address table with (adress_id,emp_num,adress,state) columns.
Now when I am inserting/updating a new record into employee table, I also want to update TEXT column for all other entries for that emp_num who are from the same state.
EMPLOYEE table:
enter image description here
Address table:
enter image description here
I am trying to do a update like below:
update employee set id_text='ABCABC' where id = 'ID1';
some other update query
after that employee table should look like:
enter image description here
(note: text field is updated for ID1 and ID4)
Thanks
To me, it looks as if you need a row-level trigger which fires whenever you insert or update a row in employee table; using :new.address_id, fetch state from address table and put it into employee's text column:
create or replace trigger trg_biu_emp
before insert or update on employee
for each row
begin
select a.state
into :new.text
from address a
where a.address_id = :new.address_id;
end;
/
UPDATE employee e
SET e.text = (SELECT a.state FROM address a WHERE a.address_id = e.address_id)
WHERE e.emp_num IN (SELECT a.emp_num FROM address a WHERE a.state = (SELECT a.state FROM address a WHERE a.address_id = e.address_id));

Make a trigger to only trigger if a certain column is updated

I'm trying to make a trigger to only trigger if a certain column is updated, and then only if the column is updated to 'Executed'. I can update if the column is changed, but I can't seem to find a way to update if column is updated to 'Executed'
CREATE TRIGGER dbo.NewTrigger
ON dbo.Database
AFTER UPDATE
AS
IF Update(Status) = 'Executed'
BEGIN
--MY insert into statement. This adds data to another table, but I only want the whole process to run if the original table column "Status" is set to "Executed"
END
Could someone assist please?
You'd need to use the inserted and deleted tables in the trigger, see here:
Use Inserted and Deleted Tables
In case of an update:
inserted table: contains new column values of rows that have been updated
deleted table: contains old column values of rows that have been updated
Your trigger could look something like this:
create table t (id int identity, status varchar(100));
create table audit(id int, old_status varchar(100), new_status varchar(100), updated_at datetime);
create trigger StatusUpdate
on t
After UPDATE as
if (update(status)
and exists(select * from inserted i
inner join deleted d on d.id = i.id
where d.status != 'Executed'
and i.status = 'Executed'))
begin
insert into audit (id, old_status, new_status, updated_at)
select i.id, d.status, i.status, getdate()
from inserted i
inner join deleted d on d.id = i.id
where d.status != 'Executed'
and i.status = 'Executed'
end
See Demo on DB Fiddle
Demo 2 - Multiple rows updated together

SQL Update in Insert clause

I have a query where I am inserting some records as long as those records do not exist in a table, but I would really like to do is to UPDATE a field of that record in that other table if it is there otherwise insert it as it is doing it right now. I would appreciate any help, or advises. Can it be done?
-- Insert into my my Toys table if record not already there (but would like to also update one of its fields)
INSERT INTO Toys (Date, ToyId)
SELECT inv.Date, inv.Id
FROM Inventory inv
JOIN InventoryStats invSt ON inv.Id = invSt.InventoryId
WHERE (invSt.IsFixed = 1 AND invSt.IsSent = 0 AND invSt.Date >= '01/01/2012 12:00 PM') AND (inv.Id NOT IN (SELECT ToyId FROM Toys))
Basically if the inv.Id is already in Toys table I do not want to insert it again but I would like to update one of its flags while on this process , like
UPDATE Toys SET NewShipDate = inv.Date WHERE ToyId = Inv.Id
You are looking for the MERGE Statement - INSERT a record if it does not exist, UPDATE it if it does.

SQL trigger on INSERT, and DELETE with 2 Tables

I've 2 tables called Patient and Diagnosis. as follows
Patient Diagnosis
--------- ------------
ID (PK) ID (PK)
Name PatientID (FK: Reference to Patient => ID)
Status
****** *****
---------- -----------
Here, Patient Status may be [Registered, Diagnosed and OnCourse]
During,
New Patient Insert, Patient Status will be Registered
New Diagnosis Insert, Patient Status will be Diagnosed
Now, On
Diagnosis Delete, I need to check If Patient has at least one Diagnosis entry in Diagnosis table, then Patient Status will be Diagnosed otherwise Registered
So, How to do all these conditions in Single Trigger?
Please help me.
Trigger to update Patient.Status based on INSERTs and DELETEs on the Diagnosis Table.
CREATE TRIGGER dbo.Diagnosis_TrgInsDel
ON dbo.Diagnosis
AFTER DELETE, INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Change the Status to 'Registered' after the last
-- Diagnosis record is deleted
--------------------------------------------------------------------------------
UPDATE
Patient
SET
[Status] = 'Registered'
FROM
Patient
INNER JOIN
Deleted
ON Deleted.PatientID = Patient.ID
WHERE
NOT EXISTS (SELECT * FROM Diagnosis WHERE PatientID = Deleted.PatientID)
-- Change the Status to 'Diagnosed' after an Insert and the
-- current Status is 'Registered'
--------------------------------------------------------------------------------
UPDATE
Patient
SET
[Status] = 'Diagnosed'
FROM
Patient
INNER JOIN
Inserted
ON Inserted.PatientID = Patient.ID
WHERE
Patient.[Status] = 'Registered'
END
I would actually have don this as two triggers. One for AFTER DELETE and one for AFTER INSERT. That would mean that the DELETE code wouldn't run when there is an INSERT and vice versa. But the above code will indeed work correctly.
EDIT
AS spotted by Nikola; if multiple diagnosise are inserted or updated, in the same operation, for the same patient, then this will potentially update a single patient record multiple times. These modifications should address that...
UPDATE
Patient
SET
[Status] = 'Registered'
WHERE
NOT EXISTS (SELECT * FROM Diagnosis WHERE PatientID = Patient.ID)
AND EXISTS (SELECT * FROM Deleted WHERE PatientID = Patient.ID)
And...
UPDATE
Patient
SET
[Status] = 'Diagnosed'
WHERE
Patient.[Status] = 'Registered'
AND EXISTS (SELECT * FROM Inserted WHERE PatientID = Patient.ID)
For the first part, you may simply add default constraint:
alter table patient add constraint df_status default 'Registered' for status
If this would not be enough because your front end is incapable of omitting status in insert or setting value to DEFAULT, you can create a trigger:
create trigger PatientInsertTrigger on patient
after insert
as
-- trigger should not alter ##rowcount
set nocount on
update patient
set status = 'Registered'
from Patient
-- Inserted is a pseudotable holding newly inserted rows
-- This is how we know what records to update
inner join Inserted
on Patient.ID = Inserted.ID
When records are added to or removed from diagnosis, patient status should be updated according to number of matching records in diagnosis. Luckily, at the time trigger is invoked records are already in table, so it is sufficient to take count() in both cases.
create trigger DiagnosisTrigger on diagnosis
after insert, delete
as
set nocount on
update patient
set status = case when d.NumberOfDiagnosis <> 0
then 'Diagnosed'
else 'Registered'
end
from Patient
inner join
(
select PatientID, count(*) NumberOfDiagnosis
from Diagnosis
-- Get all patients with added or removed diagnosis
where PatientID in (select PatientID
from Inserted
union
select PatientID
-- Pseudotable holding removed records
from Deleted)
group by PatientID
) d
on Patient.ID = d.PatientID
Status should be StatusID, but you did not mention appropriate id numbers.

Writing a complex trigger

I am using SQL Server 2000. I am writing a trigger that is executed when a field Applicant.AppStatusRowID
Table Applicant is linked to table Location, table Company & table AppStatus.
My issue is creating the joins in my query.
When Applicant.AppStatusRowID is updated, I want to get the values from
Applicant.AppStatusRowID, Applicant.FirstName, Applicant.Lastname, Location.LocNumber, Location.LocationName, Company.CompanyCode, AppStatus.DisplayText
The joins would be :
Select * from Applicant A
Inner Join AppStatus ast on ast.RowID = a.AppStatusRowID
Inner Join Location l on l.RowID = a.LocationRowID
Inner Join Company c on c.RowID = l.CompanyRowID
This is to be inserted into an Audit table (fields are ApplicantID, LastName, FirstName, Date, Time, Company, Location Number, Location Name, StatusDisposition, User)
My issue is the query for the inner join...
First lets introduce you to the inserted and deleted pseudotables which are available only in triggers. Inserted has new values and delted has old values or records being deleted.
You do not want to insert all records into your audit table only those in inserted.
So to insert into an audit table you might want something like inside the trigger code:
insert Myaudittable (<insert field list here>)
Select <insert field list here> from Inserted i
Inner Join AppStatus ast on ast.RowID = i.AppStatusRowID
Inner Join Location l on l.RowID = i.LocationRowID
Inner Join Company c on c.RowID = l.CompanyRowID
I would personally add columns for old and new values, a column for the type of change and what the date of the change and what user made the change, but you I'm sure have your own requirement to follow.
Suggest you read about triggers in Books online as they can be tricky to get right.
Here's one way to test and debug trigger that I often use. First I create temp tables names #delted and #inserted that have the sturcture of the table I'm going to put the trigger on. Then I write the code to use those instead of the deleted or inserted tables. That wa y I can look at things as I go and make sure everything is right before I change the code to a trigger. Example below with you code added in and modified slightly:
Create table #inserted(Rowid int, lastname varchar(100), firstname varchar(100), appstatusRowid int)
Insert #inserted
select 1, 'Jones', 'Ed', 30
union all
select 2, 'Smith', 'Betty', 20
Create table #deleted (Rowid int, lastname varchar(100), firstname varchar(100), appstatusRowid int)
Insert #deleted
select 1, 'Jones', 'Ed', 10
union all
select 2, 'Smith', 'Betty', 20
--CREATE TRIGGER tri_UpdateAppDisp ON dbo.Test_App
--For Update
--AS
--If Update(appstatusrowid)
IF exists (select i.appstatusRowid from #inserted i join #deleted d on i.rowid = d.rowid
Where d.appstatusrowid <> i.appstatusrowid)
BEGIN
--Insert AppDisp(AppID, LastName, FirstName, [DateTime],Company,Location,LocationName, StatusDisp,[Username])
Select d.Rowid,d.LastName, d.FirstName, getDate(),C.CompanyCode,
l.locnum,l.locname, ast.Displaytext, SUSER_SNAME()+' '+User
From #deleted d
Join #inserted i on i.rowid = d.rowid
--From deleted d
--Join inserted i on i.rowid = d.rowid
Inner join Test_App a with (nolock) on a.RowID = d.rowid
inner join location l with (nolock) on l.rowid = d.Locationrowid
inner join appstatus ast with (nolock) on ast.rowid = d.appstatusrowid
inner join company c with (nolock) on c.rowid = l.CompanyRowid
Where d.appstatusrowid <> i.appstatusrowid)
end
Once you get the data for the select correct, then it is easy to uncomment out the trigger code and the insert line and change #deleted or #inserted to deleted or inserted.
You'll note I had two records in the temp tables, one of which met your condition and one of which did not. This allows you to test mulitple record updates as well as results that meet the condition and ones that don't. All triggers should be written to handle multiple records as they are not fired row-by-row but by batch.