How to fire a trigger after finishing data insert in a table - oracle

I have a table A into which I am inserting data. Then some calculation is being done updating the same table A.
I want to fire a trigger, which calls a Procedure A after the completion of data insertion ( after insert and update ).
How do I do this?
Is there any other way to do it automatically... Or do I have to run Procedure A manualy after the completion of data insertion in table A.
More simply, I would like to know how to fire a trigger after inserting a few rows and a commit, i.e. not for each row.

You can define your trigger to be fired for each row or for each statement (FOR EACH ROW option).
If I understood you right, you would like to fire the trigger after a bunch of statements? Don't think you can. Even if you can, I would rather not do it. They scatter your program flow / logic and make it harder to understand later how your software works.
Regards

If I understand your question correctly, you want the trigger to fire after you completed your transaction consisting of several insert/update statements? If that is the case, I think you should consider calling your Procedure A in your program flow right after the insert/update operations are done.
In other words: A trigger would only be useful, if it should be called for each row or for each statement.

Add one column to your table: e.g "FINAL_ACTION". Leave this column untouched untill your anticipated final action. Then have your trigger get fired only with this clause:
REFERENCING NEW AS NEWREC OLD AS OLDREC
FOR EACH ROW
WHEN (NEWREC.FINAL_ACTION <> OLDREC.FINAL_ACTION)
DECLARE
--YOUR DECLARATIONS
BEGIN
--DO SOMETHING
END;

Related

Is it possible to create master-detail relationship in Oracle Forms when both of the blocks are based on procedure?

I have two blocks that are based on procedure and I want to create master-detail relationship between them.
I do this using Data Block Wizzard. It create trigger ON-CHECK-DELETE-MASTER, this trigger assumes that my detail block is based on table (FRL_XXX.TRIGGERS_QUERY, but it is a procedure) and generates cursor:
CURSOR TRIGGERS_cur IS
SELECT 1 FROM FRL_XXX.TRIGGERS_QUERY F
WHERE F.PTG_PST_CODE = :S_TYPES.PST_CODE;
Is there any workaround to solve this problem?
When I try delete this trigger or remove the cursor I get error:
FRM-30409: Delete Record Behavior for the relation is invalid.
I've never done that, but - let me think aloud.
If data block is based on a procedure, it means that procedure returns (as its IN OUT parameter) an array. I'd say that you'll have to
create your own trigger (i.e. replace the one created by the Wizard
note that these triggers usually have a comment "don't modify it!". If you run the Wizard again, it might overwrite your code, so safer approach is to create a procedure which will do the job, and call that procedure from the trigger
declare a local variable (array) and fetch data into it; pass all parameters to the procedure as you did while calling it in order to populate data block
review array's contents and check whether there's any row that satisfies condition PTG_PST_CODE = :S_TYPES.PST_CODE
if so, do what Wizard's trigger does in that case
Basically, I think that you'll have to write your own process which will replace default Forms behavior.
In Procedure based blocks, If you choose the Relation type as Isolated , Oracle form will allow the Master Detail relationship between two blocks because in that case ON-CHECK-DELETE-MASTER trigger won't be there.
You will be able to retrieve the records from detail block as ON-POPULATE-DETAILS trigger will work as-usual.
In my case, only detail block was based on Procedure and it's working fine.
Note : Isolated type of relationship will delete the master records even if child records exist. You need to handle this case separately.
Please share your approach step by step, if you went ahead as per littlefoot

Oracle deadlock trigger

I have a procedure P1.
TABLES T1,T2 and TRIGGER TRG1
Below is the Trigger Event:
CREATE OR REPLACE TRIGGER
AFTER UPDATE OF RECORD_STATUS
ON T1 WHEN (NEW.RECORD_STATUS='U')
BEGIN
.
--Calling Procedure
P1();
.
END;
I am calling a procedure with parameters. Inside procedure P1 using those parameters I am selecting the data from T1 and doing some validations and inserting into T2.
After Successful insert I am updating the RECORD_STATUS='I' in the the procedure.
Now I performed below statement:
UPDATE T1 SET RECORD_STATUS='U'
Since the trigger event occurs here it is calling my procedure and inside the procedure since I am updating the same column again trigger is firing and leads to dead lock. Please help me in this.
Thanks in advance.
First of all some advice, NEVER use triggers unless your desperate.
If your already updating the table in a stored procedure, add the logic into your P1 procedure, or create a second procedure with the additional functionality and call it from P1.
Good citizenship is part of database development. All transactions on those tables should follow the same order. Using a trigger to update the same table is not good citizenship.
If you really have to do something like this, one thing you can try, is to use an Autonomous Transaction

PL/SQL Trigger on INSTERT OR UPDATE : ":NEW" IS NULL => ambiguous?

I'm quite a newbie in PL/SQL and I'm trying to do quite complex data integrity checks via triggers.
I've already understood how to avoid problems when calling a table inside a trigger that is used on the same table (via a temporary external table) but now I'm facing a really mind-blowing problem : I thought that ":NEW" was referencing the value in my table AFTER an update but things don't look that simple... It is the new value SET by the update or insert... which looks to be NULL if nothing has been specified, even if the corresponding field value is NOT NULL after the update... wich is driving me crazy.
My trigger is set when inserting or updating several variables :
CREATE OR REPLACE TRIGGER TRG_INS_UP_INSTRUMENT_EVENT
AFTER INSERT OR UPDATE OF EVENT_ID, DATE_BEGIN,DATE_END,INSTR_ID,TYPE_EVENT_ID ON AIS_INSTRUMENT_EVENT
But now... If there already is a line with non-null fields and I do an
UPDATE AIS_INSTRUMENT_EVENT SET INSTR_ID='642' WHERE EVENT_ID='6479'
I actually get a ":NEW.DATE_BEGIN" which is NULL... event thought nor the older or newer values are NULL (because I just didn't update it).
How can I distinguish - in my trigger - the case when the DATE_BEGIN is updated and SET voluntary to NULL from the case in which nothing has been specified (and this field must thus remain the same but not necessarily NULL...). I have to many possible combination to check one by one...
Thanks in advance for your help!
What you are saying is not true. :new contains the full row regardless whether the column is referenced in the UPDATE statement:
CREATE TABLE test (test INTEGER, last_changed DATE);
CREATE OR REPLACE TRIGGER TRG_INS_UP_TEST
AFTER INSERT OR UPDATE OF test, last_changed ON test
FOR EACH ROW
BEGIN
dbms_output.put_line('LAST CHANGED IS ' || :new.last_changed);
END;
INSERT INTO test (test, last_changed) VALUES (1, SYSDATE);
COMMIT;
UPDATE test SET test = test + 1;
DBMS Output:
LAST CHANGED IS 01.09.17
To achieve what you want the mechanism works slightly different. You have to look at two different use cases:
1.) You want the trigger not to fire unless a certain column is mentioned. This use cases is by the reference in the trigger declaration (INSERT OR UDATE OF "column_name"). If the INSERT/UPDATE statement only affects columns that are not mentioned the trigger will not fire.
2.) You want the trigger not to fire unless a certain row is modified. So you want the trigger to only if fire is a value has actually changed. This is done by the WHEN restriction of the trigger. It is usually used in conjunction with DECODE, like so:
CREATE OR REPLACE TRIGGER TRG_INS_UP_TEST
AFTER INSERT OR UPDATE OF test, last_changed ON test
FOR EACH ROW
WHEN (DECODE(new.test,old.test,0,1)=1 OR DECODE(new. last_changed,old. last_changed,0,1)=1)
BEGIN
...
END;
So to answer your original question: If you want to the trigger too only fire in cases where the column DATE_BEGIN is set to NULL you will have to declare your trigger using both approaches
CREATE OR REPLACE TRIGGER TRG_INS_UP_INSTRUMENT_EVENT
AFTER INSERT OR UPDATE OF DATE_BEGIN ON AIS_INSTRUMENT_EVENT
FOR EACH ROW
WHEN (DECODE(new.DATE_BEGIN,old. DATE_BEGIN,0,1)=1 AND new.DATE_BEGIN IS NULL)
The limitation to certain columns ("INSERT OR UPDATE OF DATE_BEGIN") is not strictly necessary but it is good practice since it improves performance since it excludes the trigger from firing at all.
Sorry I think I made a to quick conclusion... The bug was mine. I've tested on a "Toy" table and, indeed, the :NEW was not null, even when not set by the UPDATE. I found the bug in the meantime. All this is too new to me ;-).
Sorry for disturbing.

Oracle error: ORA-04079: invalid trigger specification

I am new to Oracle and would like to know how to make this trigger work please. I can do each trigger separately but I need them all in the same one if that makes sense.
create trigger ID_trigger
before insert on crime, evidence, offence, officer
for each row
begin
select crime_seq.nextval into :new.crime_id from dual
and officer_seq.nextval into :new.officer_id from dual
and evidence_seq.nextval into :new.evidence_id from dual
and offence_seq.nextval into :new.offence_id from dual;
end;
I initially had a single trigger for each table. However when submitting data into my form the triggers seemed to have overwritten the previous one
" I initially had a singler trigger for each table, however when
sumbitting data into my form the triggers seemed to have overwritten
the previous one"
Let's guess: you called all four triggers id_trigger. Each subsequent CREATE OR REPLACE TRIGGER call would overwrite the first one. Unless you used CREATE TRIGGER as you do here, in which case each subsequent call would fail, Either way, only one table would have a trigger.
You see, even though they belong to a table, triggers are separate database objects. So, like indexes or constraints, their names must be unique within the schema.
The solution is simple: give each trigger a different name, say by including the table name.

Populate a column on update (create too?), and why "FOR EACH ROW"?

I have a table of people who belong to various sites. These sites can change, but don't very often. So when we create an attendance record (a learner_session object) we don't store the site. But this has cause a problem in reporting how many training hours a site has, because some people have changed sites over the years. Not by much, but we'd like to get this right.
So I've added a site_at_the_time column to the learner_session table. I want to auto-populate this with the site the person was at when they attended the session. But I'm not sure how to reference this. For some reason (I'm guessing to speed development or something) the learner_id is allowed to be null. So I'm currently planning to do an update trigger. The learner_id shouldn't ever get updated, and if it ever did somehow, the entire record would be junk so I'm not worried about it overwriting it.
The trigger I have now is
create trigger set_site_at_the_time
after update of learner_id on lrn_session
begin
:new.site_at_the_time:= (select site_id from learner who where :new.learner_id = who.learner_id);
end;
which leads me to the following error:
ORA-04082: NEW or OLD references not allowed in table level triggers
Now, I've done some research and found I need to use a FOR EACH ROW - and I'm wondering what exactly this FOR EACH ROW does - is it every row captured by the trigger? Or is it every row in the table?
Also, will this trigger when I create a record too? So if I do insert into learner_session(id,learner_id,...) values(learner_session_id_seq.nextval,1234,...) will this capture that appropriately?
And while I'm here, I might as well see if there's something else I'm doing wrong with this trigger. But I'm mainly asking to figure out what the FOR EACH ROW is supposed to do and if it triggers properly. =)
FOR EACH ROW means that the trigger will fire once for each row that is updated by your SQL statement. Without this clause, the trigger will only fire once, no matter how many rows are affected. If you want to change values as they're being inserted, you have to use FOR EACH ROW, because otherwise the trigger can't know which :new and :old values to use.
As written, the trigger only fires on update. To make it also fire upon insert, you'd need to change the definition:
CREATE TRIGGER set_site_at_the_time
BEFORE INSERT OR UPDATE OF learner_id
ON lrn_session
FOR EACH ROW
BEGIN
SELECT site_id into :new.site_at_the_time
FROM learner who
WHERE :new.learner_id = who.learner_id);
END set_site_at_the_time;

Resources