I have 4 tables i.e, A,B,C,D and A is parent table and b & C are child tables.For a tuning query,I am creating another table
i.e., D.In this table some fields of B & C.If any CRUD operations occurs in those two table I want insert/update into d table.So I trying to
append D table insertation in those table triggers.
CREATE OR REPLACE TRIGGER A_ADUIT_TRIGGER
BEFORE INSERT OR DELETING on per
REFERENCING NEW AS NEW OLD AS OLD
IF (INSERTING) THEN
INSERT INTO D(ID) VALUES(:OLD.ID);
ELSIF (DELETING) THEN
INSERT INTO A_AUDIT(ID,ID_NAME,TEST) VALUES(OLD.ID,OLD.ID_NAME,OLD.TEST);
END IF;
Its compiled and remaining tables trigger not included "D" TABLE inseration. When i am trying test at my application side and the logic
insert/update in table "A","B","C" and got expection that is B.ID Cannot insert null.But i have ID Value.I am suspected the issue at
insert of D table.If i remove insertation on table d in trigger and its working fine.Is it possible multiple table handled in triggers
Please help on this.
Related
Hi I need to create a new table to store the data of two tables. Then I would need to create a stored procedure to transfer the data from the two tables into the new one. I had no problem transferring the data from the first table to the new table, the problem arises when i transfer the data from the second table to the new table. Because instead of being inserted in the row that matches its pubid, it is being inserted into a new row instead.
You're quite close, I'd say.
In the second loop, you shouldn't INSERT, but UPDATE existing row.
Cursor you declared:
CURSOR cur_proceedings IS
SELECT pubid, year FROM proceedings;
You've used it here:
OPEN cur_proceedings;
LOOP
FETCH cur_proceedings INTO v_proceedings;
EXIT WHEN cur_proceedings%NOTFOUND;
-- Instead of INSERT:
-- INSERT INTO publication_master(proceeding_year)
-- VALUES(v_proceedings.year);
-- use UPDATE:
update publication_master m set
m.proceeding_year = v_proceedings.year
where m.pubid = v_proceedings.pubid;
END LOOP;
CLOSE cur_proceedings;
I have two instances of the same database, but data is only committed to the "original" one. I need to copy inserted data from certain tables and commit them to the same tables in the second DB automatically. How can I do it?
I've already created synonyms for the tables in the second DB on original and within a specially prepared trigger I tried to use INSERT INTO ... statement with :new. but it is causing the data to not be committed anywhere and I receive Oracle Errors like:
ORA-02291: integrity constraint (PRDBSHADOW.FK_ED_PHY_ENT) violated.
Here is my trigger code
create or replace TRIGGER INS_COPY_DATA
AFTER INSERT ON ORIGDB.TABLE_A
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
insert into COPY_TABLE_A(val1,val2,val3,val4) values (:new.val1, :new.val2, :new.val3, :new.val4);
END;
I think the entry in parent table is missing here. At least the FK ending of constraint is telling me so.
It means you need to insert first all the data into a "parent" table in order to be able to insert records in a "child".
For example the table auto_maker is having 3 rows only: Audi, Peugeot, and Honda.
Another table named "model" has 2 columns "maker" and "model". "maker" is a foreign key referencing to the "auto_maker" table.
It means in the models table are only the records allowed whose "maker" column value exists in "auto_maker" table.
In other words only these are available:
maker model
Audi A4
Peugeot 308
Honda Accord
Of course you can enter every model you wish, but "maker" value has to exist in the auto_maker table.
This is what probably happen - the trigger tries to insert a data in a column which is referencing to a "parent" table and the :new value just doesn't exist.
The following script will let you know what table you need to fill first.
select aic.index_owner, aic.table_name, aic.column_name
from all_constraints uc,
all_ind_columns aic
where aic.INDEX_NAME = uc.r_constraint_name
and uc.table_name = 'TABLE_A'
and uc.constraint_type = 'R';
If the query returns something just create similar triggers on those tables with similar logic you already have
I have three tables: A and B
The relationship is A can have many B
So B has a reference to the A.id as one of its columns
Table A
|id|date|...
Table B
|id|A_id|...
I have created an Oracle trigger on table A so that when it is updated it updates an A_Mod table.
This trigger is
CREATE OR REPLACE TRIGGER TR_A_INSERT_UPDATE
AFTER INSERT OR UPDATE ON A
FOR EACH ROW
BEGIN
INSERT INTO A_Mod values(..., :new.date, ...)
END;
This works fine :)
My problem si creating the trigger for table B.
The trigger is:
CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE
AFTER INSERT OR UPDATE ON B
FOR EACH ROW
DECLARE
ts TIMESTAMP;
BEGIN
SELECT aa.date INTO ts FROM B bb
INNER JOIN A aa ON a.id = bb.A_id
WHERE bb.id = :new.id;
INSERT INTO A_Mod values(..., :new.date, ...)
END;
This trigger is reading the ID of the updated line in table B and then getting the date from the corresponding row in table A. It then tries to insert it into A_Mod
The problem is I get a mutating error
Error report:
SQL Error: ORA-04091: table B is mutating, trigger/function may not see it
ORA-06512: at "TR_B_INSERT_UPDATE", line 5
ORA-04088: error during execution of trigger 'TR_B_INSERT_UPDATE'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Looking at the docs I can remove this error by removing the FOR EACH ROW line and having the trigger fire once per statement rather than once per row. Unfortunately I am using an ORM mapper so do not control how the updates happen. I think there would be times when the update could cover multiple rows.
The docs say something about creating a temporary table but I am not sure how this would help. Would I have to create a temporary table inside the trigger, create a trigger on this temporary table which then updates A_Mod, update this temporary table when the trigger is fired and then delete everything after?
Any tips greatly appreciated.
Thanks
It doesn't appear that there is any reason in your trigger on B to query the B table. You should be able to simply query A using the :new.a_id
CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE
AFTER INSERT OR UPDATE ON B
FOR EACH ROW
DECLARE
ts TIMESTAMP;
BEGIN
SELECT a.date
INTO ts
FROM A a
WHERE a.id = :new.a_id;
INSERT INTO A_Mod values(..., :new.date, ...)
END;
From a data modeling standpoint, however, I would be very concerned if a trigger on a child table needed to query any information from the parent table or to insert data into the same history table that the parent table writes to. That seems likely to indicate a normalization issue.
I have a table A which is constantly updated ( insert statements ) by one application. I want to create another table B which consists only few columns of table A. For this I thought of creating a trigger which triggered after insert on Table A, but I don't know how should I write the insert statement inside the trigger. I am not a database expert, so may be I am missing something simple. Please help.
Here is my trigger code:
CREATE OR REPLACE TRIGGER "MSG_INSERT_TRIGGER"
AFTER
insert on "ACTIVEMQ_MSGS"
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
begin
execute immediate 'truncate table MSG_BACKUP';
insert into MSG_BACKUP select * from ACTIVEMQ_MSGS;
COMMIT;
end;
This does not seem to be good idea: every time a new record gets inserted into Table A, delete everything from table B and copy all records from table A. This will be a huge performance issue, once there is many records in table A.
Wouldn't it be enough to create a view on the desired columns of table A?
If not, that is, you still want to "log" all inserts into an other table, then here you go. (I suppose you want to copy the following fields: f1, f2, f3)
CREATE OR REPLACE TRIGGER TR_AI_ACTIVEMQ_MSGS
AFTER INSERT ON ACTIVEMQ_MSGS
FOR EACH ROW
BEGIN
INSERT INTO MSG_BACKUP (f1, f2, f3)
VALUES (:new.f1, :new.f2, :new.f3);
END TR_AI_ACTIVEMQ_MSGS;
Inside an Oracle trigger the record values are available in de :new pseudo record. Your insert statement may look like this:
insert into B (column1, column2)
values (:new.tableA_col1,:new.tableA_col2)
I have a database with tables that are chained together with foreign keys, and the last one in the chain also has a foreign key to itself. I want to delete them with cascade on, exapt for the last one in the chain. That one should be set null, unless it's parent record has a certain value. I figured i would do that with a trigger: whenever the last table updated, if the foreign key to itself had been set to null, check the field in the parent record, and if it is the value "default", delete the record in the last table.
However, I haven't found any help online indicting that comparing a parent record in another table.
Is this possible?
In general, a row-level trigger on table A cannot query table A. Doing so would generally raise a mutating table exception (ORA-04091). So a trigger is generally not the right solution.
Presumably, you have some sort of API (i.e. a stored procedure) to delete records from the parent table. That API should query this last table before issuing the DELETE against the parent table. It should take care of updating the last table in the chain as well as deleting the data from the parent table.
If you really wanted a trigger-based solution, life would get substantially more complicated. You could work around the mutating table exception by
Creating a package with a collection of primary keys from the parent table
Creating a before statement trigger that initializes this collection
Creating a row-level trigger that populates the collection with the primary keys that were modified by the SQL statement
Creating an after statement trigger that iterates over the collection and issues whatever DML is necessary (unlike row-level triggers, statement-level triggers on table A can query or modify table A).
If you're using 11g, you can simplify this a bit with a compound trigger with before statement, after row, and after statement sections. But you've still got a number of moving pieces to try to coordinate.
AFAIK you won't be able to really delete the record in the last table (mutating table problem), but you could update a status field indicating the record has been logically deleted (untested):
create or replace trigger last_table_trig
before update on last_table
for each row
declare
l_parentField varchar2(100);
begin
if :new.self_ref_fk is null then
select p.parent_field into l_parentField from parent_table p
where p.pk = :new.parent_fk;
if l_parentField = 'default' then
:new.status := 'DELETED';
end if;
end if;
end;