Create trigger that updates row depending on column value from other table - oracle

I would like to create a trigger that updates a row in a table (TABLE2) depending on column value from other table (TABLE1).
Which line must be updated depends on the ID of TBL1.
CREATE OR REPLACE TRIGGER INSERT_PAGE
BEFORE UPDATE OR INSERT
ON TABLE1
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO TABLE2 (TBL1ID,STEP,PAGE) VALUES
(:NEW.TBL1ID,:NEW.STEP,15);
ELSIF UPDATING and :NEW.STATE='APPROVED' THEN
UPDATE TABLE2
SET PAGE=16 AND STEP1='TEXT123'
WHERE TBL1ID =TABLE1.TBL1ID;
END IF;
END;
Can someone help me in creating a trigger with an update statement?
Would this be as well a good way to go?
So I have two tables, the column state in table1 is changing throughtout the process.
Depending on the change of the column state from table1, I want to change or better say update the row in table 2 and set some columns like PAGE and STATE in Table 2 depending on column value STATE in Table 1.
I do not want that a new row being created each time TABLE 1 gets updated, only the corresponding row should be updated.

As far as I understood is you want to update table2 only when the state in table1 changed to 'approved' for a row and if a row is inserted in table1 trigger will insert the row in table2.
I have made some corrections to your code. Let me know if it is not what you wanted.
CREATE OR REPLACE TRIGGER INSERT_PAGE
BEFORE UPDATE OR INSERT
ON TABLE1
FOR EACH ROW
DECLARE
BEGIN
IF INSERTING THEN
INSERT INTO TABLE2 (TBL1ID,STEP,PAGE) VALUES
(:NEW.TBL1ID,:NEW.STEP,15);
ELSIF UPDATING THEN
IF :NEW.STATE = 'APPROVED' THEN
UPDATE table2 t2 SET
STATE = :NEW.STATE, PAGE=16, STEP1='TEXT123'
WHERE t2.TBL1ID = :OLD.TBL1ID;
END IF;
END IF;
END;

Related

Update trigger updating all rows in a table

I have a trigger I need to write to update a row to 'F' in a table called StudentGrades (which contains student_id, section_id, and grade) to fire when a student's status is changed to 'I' in a different table called student. My problem is I thought it worked, but it'll update all the values to 'F' no matter what the status is updated to and it updates the grades for all the student_id's in the table. Here's my code:
create or replace NONEDITIONABLE TRIGGER grades_trigger
AFTER UPDATE ON STUDENT
FOR EACH ROW
BEGIN
UPDATE StudentGRADES
SET GRADE = 'F'
WHERE :NEW.STATUS= 'I';
END ;
I can post more if I need to.
Thanks.
If I understood you correctly, that would be
create or replace noneditionable trigger grades_trigger
after update on student
for each row
begin
if :new.status= 'I' then --> is student's status changed to I?
update studentgrades set --> yes, it is - so - update another table ...
grade = 'F'
where student_id = :new.student_id; --> but not for ALL students - only for the one for which the trigger had fired
end if;
end;

Adding Data in 1 tables through trigger on multiple tables

How do I add data in a table which contains attributes of two different tables which are not linked together?
Table 1 has col1,col2,col3 (assume all are numbers)
Table 2 has col4,col5,col6 (assume all are numbers)
Table 3 has A,B,C,D,E,F (assume all are numbers)
Question is that if any insertion occurs on table 1 and table 2, their data should be loaded in table 3.
I used the normal approach
of
create or replace trigger trig_name
before insert on table1,table2 --> not allowed
for each row
begin
if inserting then
insert into table3 values (:new.col1,:new.col2,:new.col3,:new.col4,:new.col5,:new.col6)
end if;
end;
/
So if I have to make two different triggers for table 1 and table 2, wouldn't that create two rows of data leaving some columns null?
Although creating a view as suggested by #EdStevens is (IMO) a superior answer, what you want can be done. And yes it requires 2 triggers. In Oracle, and all other DBMS that I'm aware of, a trigger can only fire on 1 table.
However, they can be reduced somewhat. There is no need for the "if inserting" test. The trigger is declared as "on insert" therefore the test will always be true. The actual issue it you cannot refer columns from table2 in the table1 trigger and likewise the other way around. What you need is to name the columns you are inserting, actually always a better approach. So:
create or replace trigger table1_bir
before insert on table1
for each row
begin
insert into table3(col1, col2, col3)
values (:new.col1,:new.col2,:new.col3);
end;
/
create or replace trigger table2_bir
before insert on table2
for each row
begin
insert into table3(col4, col5, col6)
values (:new.col4,:new.col5,:new.col6);
end;
/

Trigger in oracle. Update field when insert or update another field

I need To update the field DATAMARKER"of my table LOG_ALARMA when I have one INSTER or UPDATE of "CONTADOR".
i have this, but return muting error.
create or replace TRIGGER TRIGGER2
AFTER INSERT OR UPDATE OF CONTADOR ON LOG_ALARMA
for each row
BEGIN
UPDATE LOG_ALARMA a
SET a.DATAMARKER=(SYSDATE);
END;
I look another examples and they work but i can't execute this correctly.
IF i comment the line for each row in my trigger body then it is working fine but it UPDATES all the rows in my table.
You do not issue an update SQL statement, because that would again cause the trigger to fire.
Instead, you just set the value :new.DATAMARKER to sysdate, using PL/SQL not SQL.
Make it a BEFORE INSERT OR UPDATE also.
CREATE TABLE Mutating
(
ID1 NUMBER,
DATE1 DATE
)
data present in a table is
ID1 DATE1
1 09/01/2015 14:09:14
1 08/31/2015 14:09:21
2 08/30/2015 14:09:30
Now i want to update the date1 if any update happens on id1 column in that situation i have used trigger look below.
CREATE OR REPLACE TRIGGER Mutating_trg
before INSERT OR DELETE OR UPDATE ON Mutating
referencing old as old new as new
for each row
begin
if updating then
:new.date1:=sysdate;
end if;
end;
then i have issued update statement
update set Mutating id1=6 where trunc(date1)=trunc(sysdate-2)
1 row updated
Now look into results
ID1 DATE1
1 09/01/2015 14:09:14
6 09/02/2015 14:09:14
2 08/30/2015 14:09:30
You should use before statement.

PLSQL Trigger to update field value in another table

I am quite new to triggers so obviously I am doing something wrong somewhere. I am working on a report table which will get the data from original tables. For the sake of simplicity, let's say that there is one table and then there is one reporting table.
Original table (orig_tab)
CREATE TABLE orig_tab (
PK NUMBER(8) not null,
NAME VARCHAR2(20) ,
);
INSERT INTO orig_tab (PK, NAME) VALUES (1, 'AAA');
INSERT INTO orig_tab (PK, NAME) VALUES (2, 'BBB');
INSERT INTO orig_tab (PK, NAME) VALUES (3, 'CCC');
Then there is reporting table (rep_tab)
CREATE TABLE rep_tab (
PK NUMBER(8) not null,
NAME VARCHAR2(20) ,
);
Now from user inteface, someone changes the value of record 2. Obviously, this should be treated as an insert (because this record doesn't exist) for reporting table. Then after sometime, the value is changed so it is an update case for reporting table.
Question: How may I make this kind of trigger? I assume that it is a merge statemement case.
This is what I have done:
create or replace trigger vr_reporting_trigger
after update on orig_tab
for each row
begin
MERGE INTO rep_tab d
USING (SELECT pk FROM orig_tab) s
ON (d.pk = s.pk)
WHEN MATCHED THEN
UPDATE SET d.pk = s.pk,
d.name = s.name
WHEN NOT MATCHED THEN
INSERT (d.pk, d.name) VALUES (s.pk, s.name);
end vr_reporting_trigger;
Any suggestions or recommendations that can help me to figure it out? Thanks.
There are some corner cases that aren't handled in previous answers.
What if a matching pk already exists in the reporting table, when a row is inserted. (We wouldn't normally expect this to happen, but consider what would happen if someone deleted a row from the orig_tab, and then inserted it again. (This is the kind of problem that's going to crop up in production, not in test, at the most inopportune time. Better to plan for it now.)
BEGIN
IF inserting THEN
-- insure we avoid duplicate key exception with a NOT EXISTS predicate
INSERT INTO rep_tab(pk,name)
SELECT :new.pk, :new.name FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM rep_tab WHERE pk = :new.pk);
-- if row already existed, there's a possibility that name does not match
UPDATE rep_tab t SET t.name = :new.name
WHERE t.pk = :new.pk;
-- could improve efficiency of update by checking if update is actually
-- needed using a nullsafe comparison ( t.name <=> :new.name );
ELSIF updating THEN
-- handle updates to pk value (note: the row to be updated may not exist
-- so we need to fallthru to the merge)
IF :new.pk <> :old.pk THEN
UPDATE rep_tab t
SET t.pk = :new.pk
, t.name = :new.name
WHERE t.pk = :old.pk ;
END IF;
MERGE INTO rep_tab d
USING DUAL ON (d.pk = :old.pk)
WHEN MATCHED THEN
UPDATE SET d.name = :new.name
WHEN NOT MATCHED THEN
INSERT (d.pk,d.name) VALUES (:new.pk,:new.name);
END IF;
END;
Merge statement sounds like a plan, except that the trigger won't fire when you're doing the first insert because you've mentioned it's an AFTER UPDATE trigger, not an AFTER INSERT trigger.
Also, the SELECT pk FROM orig_tab will result in Mutating table problem.
Better way would be to define an AFTER INSERT OR UPDATE trigger, combine it with INSERT/UPDATING keywords to handle inserts/updates & use :new/:old to handle new data & old data respectively.
CREATE OR replace TRIGGER vr_reporting_trigger
AFTER INSERT OR UPDATE ON orig_tab
FOR EACH ROW
BEGIN
IF inserting THEN
INSERT INTO rep_tab
(pk,
name)
VALUES (:NEW.pk,
:NEW.name);
ELSIF updating THEN
UPDATE rep_tab r
SET name = :NEW.name
WHERE r.pk = :old.pk;
END IF;
END vr_reporting_trigger;
This is an Extension of Sathya Answer as Jaanna asked about if the record is updating in orrig_tab and no corresponding record in rep_tab then the below logic will cater the request below .Please don't judge me with this answer as this solution belongs to Sathya
CREATE OR replace TRIGGER vr_reporting_trigger
AFTER INSERT OR UPDATE ON orig_tab
FOR EACH ROW
BEGIN
IF inserting THEN
INSERT INTO rep_tab
(pk,
name)
VALUES (:NEW.pk,
:NEW.name);
ELSIF updating THEN
MERGE INTO rep_tab d
USING DUAL
ON (d.pk =:OLD.pk)
WHEN MATCHED THEN
UPDATE SET d.name = :OLD.name
WHEN NOT MATCHED THEN
INSERT (d.pk,d.name) VALUES (:OLD.PK,:NEW.PK );
END IF;
END vr_reporting_trigger;

Bulk Update from one table to another

So I tried the bulk update in order to copy values from uemte_id column in pp_terminal table to uemte_id column (null at start) in mm_chip table. These two tables have no columns in common.This is what I used:
declare
type ue_tab is table of
pp_terminal.uemte_id%type;
ue_name ue_tab;
cursor c1 is select uemte_id from pp_terminal;
begin
open c1;
fetch c1 bulk collect into ue_name;
close c1;
-- bulk insert
forall indx in ue_name.first..ue_name.last
update mm_chip set uemte_id = ue_name(indx);
end;
/
And this is the error message I get:
Error report:
ORA-00001: unique constraint (DPOWNERA.IX_AK7_MM_CHIP) violated
ORA-06512: at line 13
00001. 00000 - "unique constraint (%s.%s) violated"
*Cause: An UPDATE or INSERT statement attempted to insert a duplicate key.
For Trusted Oracle configured in DBMS MAC mode, you may see
this message if a duplicate entry exists at a different level.
*Action: Either remove the unique restriction or do not insert the key.
Do you see any obvious misstakes?
What you're trying to do is:
select a row from the first table
update every row in the second table with that value
select another row from the first table
update every row in the second table with that value
and so forth until the loop finishes
I'm guessing that's not what you really want to do. It's failing because you have a unique constraint so you're not allowed to have multiple rows in the second table with the same value.
Below is one way to update each row of one table based on the value of an arbitrary row in a second table, without reusing any rows from the second table. It would perform better if you could do it entirely in SQL, but I couldn't come up with a way to do that.
CREATE TABLE test4 AS
(SELECT LEVEL AS cola, CAST(NULL AS number) AS colb
FROM DUAL
CONNECT BY LEVEL <= 100);
CREATE TABLE test5 AS
(SELECT 100 + LEVEL AS colc
FROM DUAL
CONNECT BY LEVEL <= 99);
DECLARE
CURSOR cur_test4 IS
SELECT *
FROM test4
FOR UPDATE ;
CURSOR cur_test5 IS
SELECT * FROM test5;
r_test5 cur_test5%ROWTYPE;
BEGIN
OPEN cur_test5;
FOR r_test4 IN cur_test4 LOOP
FETCH cur_test5 INTO r_test5;
IF cur_test5%NOTFOUND THEN
EXIT;
END IF;
UPDATE test4
SET colb = r_test5.colc
WHERE CURRENT OF cur_test4;
END LOOP;
CLOSE cur_test5;
END;

Resources