Autonomous Trigger / Mutating Table Problem

We have a specific problem in one of our applications being developed where by the database needs to enforce a specific business requirement.
We need to use a database trigger to enforce some data integrity which involves more than one table as such cannot use standard constraint. The integrity has to be maintained in the database as the DML statements may be coming from a Java application or PL/SQL code as such we need the logic all in one place.
The problem being that within the trigger we need to examine the state of the table the trigger is associated with as well as one other table. Obviously using a trigger on a table that is being affected by DML statements causes the dreaded mutating table problem.
One suggested solution to this was to make the trigger or the code the trigger called autonomous. This allows the trigger to execute by only showing the trigger the original state of the table before any of the DML statements have affected it.
The problem is this seems to work for single row DML statements but not for multi row DML statements. In multi row the trigger only sees the original state of the table, not the state of the table plus the changes made by any other actions in the same DML statement.
Below I have shown an example of what I'm seeing.
I have grossly simplified the example code below to only refer to a single table and use stupidly simple logic
I do realise i appear to be implementing uniqueness in my own PL/SQL code, this is purely for the example.
CREATE TABLE mutate_test
id INTEGER NOT NULL,
value VARCHAR2(255) NOT NULL
ALTER TABLE mutate_test ADD CONSTRAINT pk_mutate_test PRIMARY KEY(id);
ALTER TABLE mutate_test ADD CONSTRAINT ck_mutate_test CHECK (value = UPPER(value));
CREATE OR REPLACE FUNCTION duplicate_found(in_value IN mutate_test.value%TYPE) RETURN BOOLEAN IS
PRAGMA AUTONOMOUS_TRANSACTION;
v_value_found INTEGER;
BEGIN
SELECT COUNT(*)
INTO v_value_found
FROM mutate_test
WHERE value = in_value;
IF v_value_found > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
CREATE OR REPLACE TRIGGER tr_mutate_test BEFORE INSERT OR UPDATE ON mutate_test
FOR EACH ROW
BEGIN
IF duplicate_found(:new.value) = TRUE THEN
RAISE_APPLICATION_ERROR(-20000,'Duplicate value found');
END IF;
END;
INSERT INTO mutate_test (id,value) VALUES (1,'CLIFF');
INSERT INTO mutate_test (id,value) VALUES (2,'SULA');
COMMIT;
SELECT * FROM mutate_test;
-- Should fail as row 1 already has a value of CLIFF
INSERT INTO mutate_test (id,value) VALUES (3,'CLIFF');
COMMIT;
SELECT * FROM mutate_test;
-- Should fail as row 1 is already set to CLIFF
UPDATE mutate_test SET value = 'CLIFF' WHERE id = 2;
COMMIT;
SELECT * FROM mutate_test;
UPDATE mutate_test SET value = 'CLIFFORD' WHERE id = 1;
COMMIT;
SELECT * FROM mutate_test;
INSERT INTO mutate_test (id,value) VALUES (3,'RONNY');
INSERT INTO mutate_test (id,value) VALUES (4,'TIM');
INSERT INTO mutate_test (id,value) VALUES (5,'MONIQUE');
COMMIT;
SELECT * FROM mutate_test;
-- Wanted result would be row 1 would be updated from CLIFFORD to CLIFF
-- and the others raise errors, or all of them raise errors.
UPDATE mutate_test SET value = 'CLIFF' WHERE id IN (1,3,4);
COMMIT;
SELECT * FROM mutate_test;

This is all from a University application that deals with eLearning.
Shell = Mapping from the system to an external eLearning application, ie: unique id of the Blackboard course shell, or WebBoard board.
Term = Academic term
Sector = University sector, ie: Higher Education, TAFE, etc..
Resource = eLearning tool, ie: Blackboard, WebBoard, etc..
Resource Level = Whether the resource is being offered at a Course or Program level
Resource Mapping = Association of a resource to shell
What we are trying to achieve is that shells cannot be used across sector boundaries.
The real table structure is (grossly simplified again)
CREATE TABLE sector (sector_pk INTEGER PRIMARY KEY);
CREATE TABLE sector_pattern (sector_pk INTEGER REFERENCES sector(sector_pk), pattern CHAR(2) NOT NULL UNIQUE CHECK (pattern = UPPER(pattern)));
CREATE TABLE term (term_pk INTEGER PRIMARY KEY, term CHAR(4) NOT NULL UNIQUE CHECK (term = UPPER(term)));
CREATE TABLE resource_level (resource_level_pk INTEGER PRIMARY KEY, term_pk INTEGER REFERENCES term(term_pk));
CREATE TABLE shell_detail (shell_detail_pk INTEGER PRIMARY KEY);
CREATE TABLE resource_mapping (resource_mapping INTEGER PRIMARY KEY, resource_level_pk INTEGER REFERENCES resource_level(resource_level_pk), shell_detail_pk INTEGER REFERENCES shell_detail(shell_detail_pk));
Based on the Ask Tom article linked I'd liked to use a MATERIALIZED VIEW on the following query
SELECT DISTINCT rm.shell_detail_pk,sp.sector_pk
FROM resource_mapping rm, resource_level rl, term t, sector_pattern sp
WHERE rm.resource_level_pk = rl.resource_level_pk
AND rl.term_pk = t.term_pk
AND SUBSTR(t.term,3,2) = sp.pattern;
Then apply a UNIQUE constraint on that VIEW.
But I'm receiving a
SQL Error: ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
I'm not sure how to create the MATERIALIZED VIEW LOG entries for the above VIEW.
Any ideas anyone? ;)
Need to do some more reading and research but as Tom says
"I'm asking around about the future of "SQL" as far as enhancments go like that
(will update when I get some feedback), but -- you are not limited to triggers
(in fact, I would avoid triggers as it is virtually IMPOSSIBLE to implement
cross row/cross object constraints with them!!!! at least correctly)"
So I think i'll give up on the TRIGGER approach as it doesn't meet our requirements.

Similar Messages

  • Mutating table problem help required

    Hi. I am rather hoping someone will be able to help me with this problem.
    I have two tables, sa and mv. Create script below:
    create table mv (
    moduleId Char(2) CONSTRAINT ck_moduleId CHECK(moduleId in ('M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8')),
    credits Number(2) CONSTRAINT ck_credits CHECK(credits in (10, 20, 40)),
    constraint pk_mv primary key(moduleId)
    create table sa (
    stuId Char(2) CONSTRAINT ck_stuId CHECK(stuId in ('S1', 'S2', 'S3', 'S4', 'S5')),
    moduleId Char(2),
    constraint pk_sa primary key(stuId, moduleId),
    constraint fk_moduleid foreign key(moduleId) references mv(moduleId)
    And the scripts below is to insert data into both:
    insert into mv VALUES('M1', 20)
    insert into mv VALUES('M2', 20)
    insert into mv VALUES('M3', 20)
    insert into mv VALUES('M4', 20)
    insert into mv VALUES('M5', 40)
    insert into mv VALUES('M6', 10)
    insert into mv VALUES('M7', 10)
    insert into mv VALUES('M8', 20)
    insert into sa VALUES('S1', 'M1')
    insert into sa VALUES('S1', 'M2')
    insert into sa VALUES('S1', 'M3')
    insert into sa VALUES('S2', 'M2')
    insert into sa VALUES('S2', 'M4')
    insert into sa VALUES('S2', 'M5')
    insert into sa VALUES('S3', 'M1')
    insert into sa VALUES('S3', 'M6')
    Now for the actual problems.
    Firstly I need to try and overcome the mutating table problem by ensure that stuid = S1 in table sa can not take both moduleId M5 and M6.
    Just one or the other. I have created a single trigger, but if fails because of the mutating table problem.
    The second problem I need to overcome is that none of the stuids can have moduleIds where total credit value of more than 120 credits. Credit value is stored in the mv table.
    Many thanks in advance for any assistance.

    Use a statement level trigger:
    Firstly I need to try and overcome the mutating table problem by ensure that stuid = S1 in table sa can not take both moduleId M5 and M6.
    SQL> create or replace trigger sa_trg
      2  after insert or update on sa
      3  declare
      4  c number;
      5  begin
      6    select count(distinct moduleId) into c
      7    from sa
      8    where stuid = 'S1'
      9    and moduleId in ('M5','M6');
    10    if c > 1 then
    11       raise_application_error(-20001,'S1 on both M5 and M6!!');
    12    end if;
    13  end;
    14  /
    Trigger created.
    SQL> select * from sa;
    ST MO
    S1 M1
    S1 M2
    S1 M3
    S2 M2
    S2 M4
    S2 M5
    S3 M1
    S3 M6
    8 rows selected.
    SQL> insert into sa values ('S1','M5');
    1 row created.
    SQL> insert into sa values ('S1','M6');
    insert into sa values ('S1','M6')
    ERROR at line 1:
    ORA-20001: S1 on both M5 and M6!!
    ORA-06512: at "SCOTT.SA_TRG", line 9
    ORA-04088: error during execution of trigger 'SCOTT.SA_TRG'
    The second problem I need to overcome is that none of the stuids can have moduleIds where total credit value of more than 120 credits. Credit value is stored in the mv table
    SQL> create or replace trigger sa_trg
      2  after insert or update on sa
      3  declare
      4  c number;
      5  begin
      6    select count(distinct moduleId) into c
      7    from sa
      8    where stuid = 'S1'
      9    and moduleId in ('M5','M6');
    10    if c > 1 then
    11       raise_application_error(-20001,'S1 on both M5 and M6!!');
    12    end if;
    13 
    14    select count(*) into c from (
    15    select stuid
    16    from mv, sa
    17    where sa.moduleid=mv.moduleid
    18    group by stuid
    19    having sum(credits)>120);
    20 
    21    if c > 0 then
    22       raise_application_error(-20002,'A student cannot have more than 120 credits!!');
    23    end if;
    24 
    25  end;
    26  /
    Trigger created.
    SQL>   select stuid, sum(credits)
      2  from mv, sa
      3  where sa.moduleid=mv.moduleid
      4  group by stuid;
    ST SUM(CREDITS)
    S3           30
    S2           80
    S1          100
    SQL> insert into sa
      2  values ('S1','M4');
    1 row created.
    SQL>   select stuid, sum(credits)
      2  from mv, sa
      3  where sa.moduleid=mv.moduleid
      4  group by stuid;
    ST SUM(CREDITS)
    S3           30
    S2           80
    S1          120
    SQL> insert into sa
      2  values ('S1','M7');
    insert into sa
    ERROR at line 1:
    ORA-20002: A student cannot have more than 120 credits!!
    ORA-06512: at "SCOTT.SA_TRG", line 20
    ORA-04088: error during execution of trigger 'SCOTT.SA_TRG'Max
    http://oracleitalia.wordpress.com

  • Trigger & Mutating Tables (Parent-Child relationship, Referencing Constraint related)

    Dear Sir,
    Wish you a very Happy New Year !!!
    I am facing a problem related to Database Trigger.
    Sir, I have two tables Cust and Sick.
    Cust is having the following fields :
    SDF_CUST_BRCD NOT NULL NUMBER(5)
    CUST_CUSTID NOT NULL VARCHAR2(6)
    UCD_CUST_SEGMENTCODE NOT NULL VARCHAR2(7)
    CUST_FIRSTBORROWER NOT NULL VARCHAR2(30)
    UCD_CUST_CONSTORGCODE NOT NULL VARCHAR2(7)
    VLGC_CUST_VILLAGECODE VARCHAR2(4)
    CUST_PAN VARCHAR2(20)
    UCD_CUST_STAFFCODE VARCHAR2(7)
    CUST_RESIDENTSTATFLAG VARCHAR2(1)
    CUST_BKGSINCEDATE DATE
    UCD_CUST_SICKUNITCODE VARCHAR2(7)
    Cust's Primary Key is the combination of Brcd, CustId
    And Sick Table Structure is as under :
    PRDT_SICK_REPORTDATE NOT NULL DATE
    CUST_SICK_BRCD NOT NULL NUMBER(5)
    CUST_SICK_CUSTID NOT NULL VARCHAR2(6)
    UCD_SICK_REASONCODE NOT NULL VARCHAR2(7)
    SICK_SINCEDATE NOT NULL DATE
    SICK_LOSSMAKINGDATE DATE
    SICK_ACCMLOSSAMT NUMBER(16,2)
    UCD_SICK_VIABILITYCODE NOT NULL VARCHAR2(7)
    UCD_BIFR_STATUS_CODE VARCHAR2(7)
    SICK_BIFRDATE DATE
    SICK_REHABSANCDATE DATE
    CUST_SICK_SICKUNITCODE VARCHAR2(7)
    Sick's Primary Key is the combination of ReportDate, BrCD, Custid
    Sick's (Brcd and Custid) referencing to Cust (BrCd, CustId).
    I want to insert/update into the sick table corrponding to Cust
    Insertion/Updation.
    I have written a trigger on Cust which is working fine provided
    that foreign key constraint
    is diabled. As soon as constraint is enabled the trigger is
    giving error
    ORA-04091: table CIS.CUST is mutating, trigger/function may not
    see it
    Sir, It is also working fine if the record is already exist in
    Sick table.
    Is is not working in 2 cases :
    1. While entering a new record into the Cust with
    SICKUNIT_CODE='SW00001'
    2. If we are changing the SickUnit_Code in Cust and correponding
    record doesn't exist in Sick.
    Please write me the solution.
    Thanking you
    yours sincerely
    Rajesh Kumar Jain
    Trigger Text is
    create or replace trigger tr_cust_sick
    after insert or update on Cust for each row
    declare
    Fn_Return boolean;
    Tr_Exception Exception;
    begin
    Fn_Return := Fn_cust_sick
    (:new.UCD_CUST_SICKUNITCODE,:new.SDF_CUST_BRCD,:new.CUST_CUSTID,I
    NSERTING,UPDATING,DELETING);
    If Not Fn_Return then
    Raise Tr_Exception;
    End if;
    exception
    when Tr_Exception then
    Dbms_output.put_line('Tr_Exception ' ||Sqlerrm);
    When others then
    Dbms_output.put_line(Sqlerrm);
    end;
    Function Text is :
    $$$$$$$$$
    create or replace function fn_cust_sick
    (SickUnitCode_in In Cust.Ucd_Cust_SickunitCode%Type,Brcd_in In
    Sdf.Sdf_Brcd%Type,Custid_in In Cust.Cust_Custid%
    Type,Inserting_in In Boolean ,Updating_in In Boolean,Deleting_in
    In Boolean)
    return boolean is
    ddate date default '01-Jul-1955';
    repdate ppar.ppar_reportdate%type default '31-Mar-2001';
    viabcode sick.ucd_sick_viabilitycode%type default 'VI00000';
    ReasonCD sick.ucd_sick_reasoncode%type default 'SK00000';
    Ret_Flag Boolean := False;
    begin
    if Updating_in then
    begin
    update sick
    set CUST_SICK_SICKUNITCODE = SickUnitCode_in
    where prdt_sick_reportdate = repdate and
    cust_sick_brcd = Brcd_in and
    Cust_Sick_CustId = Custid_in;
         Ret_Flag := True;
    if sql%notfound then
    if To_Number(Substr(SickUnitCode_in,3)) > 0 then
    insert into sick
    (PRDT_SICK_REPORTDATE,
    CUST_SICK_BRCD,
    CUST_SICK_CUSTID,
    UCD_SICK_REASONCODE,
    SICK_SINCEDATE,
    UCD_SICK_VIABILITYCODE,
    CUST_SICK_SICKUNITCODE,
              SUBO_SICK_SICKBORRCODE)
    values
    (repdate,
    Brcd_in,
    Custid_in,
    reasoncd,
    ddate,
    viabcode,
    SickUnitCode_in,
              'SB00001');
    Ret_Flag := True;
         Return(Ret_Flag);
         end if;
    end if;
    exception
    when others then
    dbms_output.put_line('Exception Update '|| Sqlerrm);
    return(Ret_Flag);
    end;
    elsif Inserting_in then
    begin
    if To_Number(Substr(SickUnitCode_in,3)) > 0 then
    insert into sick
    (PRDT_SICK_REPORTDATE,
    CUST_SICK_BRCD,
    CUST_SICK_CUSTID,
    UCD_SICK_REASONCODE,
    SICK_SINCEDATE,
    UCD_SICK_VIABILITYCODE,
    CUST_SICK_SICKUNITCODE,
              SUBO_SICK_SICKBORRCODE)
    values
    (repdate,
    Brcd_in,
    Custid_in,
    reasoncd,
    ddate,
    viabcode,
    SickUnitCode_in,
              'SB00001');
    Ret_Flag := True;
    end if;
         Return(Ret_Flag);
    exception
    when others then
    dbms_output.put_line('Exception Insert '|| Sqlerrm);
    return(Ret_Flag);
    end;
    end if;
    return(Ret_Flag);
    exception
    when Others then
    dbms_output.put_line('Main Exception '|| Sqlerrm);
    return(Ret_Flag);
    end;
    $$$$$$$$$$$

    Hi,
    double click the Application Module to open the AM editor. Select the data Model category. On the right hand side you see what is selected for use in an application, on the left hand side is what you have available as View Object. To create T1-->T2-->T3, you
    - Select T1 and move it to the right
    - Select T2 under T1 on the left and move it to the right under T1
    - Select T3 under T2 on the left and move it under T2 in T1 on the right
    Frank

  • Mutating table problem

    We have a problem using the productivity booster "Maintain DB-package to support businees rule implementation". After running the utility we get the message: Kxception; Note that the text for this element may have been corrupted". The package is created, but the code is corrupted indeed.
    We are using Designer6.0 an Headstart 2.1.2, patch11.
    Our problem resembles the problem issued by Hans van Beek on january 11, 2001
    Thanks in advance

    <BLOCKQUOTE><font size="1" face="Verdana, Arial">quote:</font><HR>Originally posted by Headstart Team:
    Benno,
    I had this problem myself a while ago and I'm not 100% sure of my solution, but I figured out it had something to do with the add_line procedure in the productivity booster.
    edit package hsu_ccmr.pkb in the hsu\scripts directory and replace the the following lines in procedure add_line:
    l_block(l_number_of_lines) := p_text_line;
    l_number_of_lines := l_number_of_lines + 1;
    with
    l_number_of_lines := l_number_of_lines + 1;
    l_block(l_number_of_lines) := p_text_line;
    So first increment the counter. I'm not sure this is the complete solution I made but give it a try!
    Recreate the package body under the utilites owner schema and run the utility again.
    Regards, Marc<HR></BLOCKQUOTE>
    Marc,
    We have found the solution in the tapi's.
    Whe have deleted the old code and generated table api's. It was a lot of work but it works.
    Thank you for your reply
    null

  • Updating a mutating table

    I have a after row trigger on a table which extracts data from another database through a database link. On insert/update of the row it updates the requisite tables in the database on which it is created.An exception is returned when if the rows are not inserted for any reason. This is to be updated in the triggering table column.Can you write a Stored Procedure to update the triggering table and avoid mutating table problem

    If you just want to update the triggering row with some specific value, then simply assign
    :new.columnname := 'some value';
    If you need to identify other rows in the same table, it's more complicated because the data is a state of flux. Potentially there are other triggers still to fire, in an unkown order, that could change the results of any query.

  • Mutating Table values

    I am facing problem when i have to insert more than 2 records to a certain table where in 1 record i have suppose RS 10 debit amount, against that i enetered 2 records thro' form ,i have to write trigger which will fire is the credit amounts which r to be entered against that debit amount should matched..but when i can't make group by in trigger since i required some values which r to be supplied to cursor..& it will possible only if i write for each row..but for each row i will not be able to group by .. the code is
    CREATE OR REPLACE TRIGGER FAS.&TRIGGER_NAME
    BEFORE INSERT
    ON &TABLE_NAME
    REFERENCING NEW AS NEW OLD AS OLD
    FOR EACH ROW
    DECLARE
    CURSOR CUR_DB_CR IS
         SELECT SUM(TR_ACCT_AMT),ACCT_AMT_DCIND
         FROM &TABLE_NAME
         WHERE COMPANY_CD = :NEW.company_cd
         AND PERIOD_CD = :NEW.period_cd
         AND TR_CD = :NEW.tr_cd
         AND DOC_NO = :NEW.doc_no
         AND DOC_DT = :NEW.doc_dt
         GROUP BY ACCT_AMT_DCIND ;
    lv_DB_TR_ACCT_AMT NUMBER ;
    lv_CR_TR_ACCT_AMT NUMBER ;
    lv_TR_ACCT_AMT NUMBER;
    lv_ACCT_AMT_DCIND VARCHAR2(1);
    BEGIN
    OPEN CUR_DB_CR ;
    LOOP
    FETCH CUR_DB_CR INTO lv_TR_ACCT_AMT,lv_ACCT_AMT_DCIND ;
    EXIT WHEN CUR_DB_CR%NOTFOUND ;
    IF lv_ACCT_AMT_DCIND = 'D' THEN
         lv_DB_TR_ACCT_AMT := lv_TR_ACCT_AMT;
    END IF ;
    IF lv_ACCT_AMT_DCIND = 'C' THEN
         lv_CR_TR_ACCT_AMT := lv_TR_ACCT_AMT;
    END IF ;
    END LOOP ;
    -- IF CUR_DB_CR%ROWCOUNT >= 2 THEN     
    IF lv_DB_TR_ACCT_AMT <> lv_CR_TR_ACCT_AMT THEN
         RAISE_APPLICATION_ERROR(-20055,'*START* Can Not INSERT..DEBIT CREDIT AMOUNT MISMATCH...! END');
    END IF ;
    -- END IF;
    CLOSE CUR_DB_CR;
    END ;

    The Mutating Table problem is tricky and difficult. First of all, I would ask for help on the database form rather than here.
    If you want your trigger to access and update other rows in the same table when you update or insert a row, you need to create several triggers, and they need to store and access data in a database package. There are some pointers on the Ask Tom website within Oracle.
    Good luck.

  • Mutating Error problem using audit trigger for UPDATE

    I need to add 4 columns to all of my tables named:
    INSERT_BY
    INSERT_DATA
    UPDATE_BY
    UPDATE_DATE
    I intend these to act as "inserted" and "last updated" audit trails within the table, as opposed to creating a new table and storing the audit information there. The insert columns appear to be easy, as I can just use a DEFAULT clause within the definition of the table. However when I attempted to write a (my first) trigger then I run into problems with mutating tables. Presumebly because I am attempting to change the table while the trigger is referencing it.
    create or replace trigger test_audit
    after update on dictionary
    begin
    update dictionary
    set update_by = user, update_date = sysdate
    where entity_id = :old.entity_id;
    end;
    I thought I could maybe get around this by calling a procedure from inside the trigger. Something like:
    create or replace procedure test_audit(vColumn in varchar2, vData in varchar2, vTable in varchar2) is
    -- vTable is table name
    -- vColumn is PK of table
    -- vData is value of PK in current row
    begin
    update vTable
    set update_by = user, update_date = sysdate
    where vColumn = vData;
    commit;
    end test_audit;
    However I cannot use variable for table names. Will this mean I have to create a procedure for each table/trigger? Is there a way to reference the table name as a variable and keep this a generic procedure? Or is there an easier way to record the auditing UPDATE information for each changed row within the original table?
    Many thanks in advance......

    Will
    this mean I have to create a procedure for each
    table/trigger? I think you've answered that question already.
    Is there a way to reference the table
    name as a variable and keep this a generic procedure?Not that I'm aware of.
    Or is there an easier way to record the auditing
    UPDATE information for each changed row within the
    original table?Well, there's the AUDIT feature.
    C.

  • Mutating table error in Trigger

    i was asked to create a trigger like...
    1. whenever a row inserted into TFILE, a select statment will be used to bring some data from different tables using a join(including FILE_TABLE)
    and then inserting selected values into a new table NEW_TAB.
    2. whenever a row Deleted from TFILE table, That curresponding row should be deleted from NEW_TAB.
    i Tried Like....
    create or replace
    TRIGGER my_trigger
    AFTER INSERT OR DELETE
    ON tfile
    FOR EACH ROW
    DECLARE
    V_FILE_ID NUMBER(8);
    V_PROP_ID NUMBER(8);
    V_DOC_ID NUMBER(8);
    V_TEMP_FILE_ID NUMBER(8);
    BEGIN
    IF INSERTING THEN
    SELECT B.DOC_ID,
    B.PROP_ID,
    A.FILE_ID
    INTO V_DOC_ID,
    V_PROP_ID,
    V_FILE_ID
    FROM (SELECT DOC_ID,
    FILE_ID
    FROM DOC_FILE
    WHERE FILE_ID = (SELECT FILE_ID
    FROM TFILE
    WHERE FILE_ID = :NEW.FILE_ID)) A ,
    DOC_OPPT B
    WHERE B.DOC_ID = A.DOC_ID;
    INSERT INTO NEW_TAB (SNO,FILE_ID,PROP_ID,DOC_ID)VALUES(CUST_COR_SEQ.NEXTVAL,V_FILE_ID,V_PROP_ID,V_DOC_ID);
    END;
    ELSIF DELETING THEN
    DELETE FROM NEW_TAB WHERE FILE_ID = :OLD.FILE_ID;
    END IF;
    ==================================================================
    I am getting error like..
    ORA-04091: table STARS.TFILE is mutating, trigger/function may not see it
    ORA-06512: at "STARS.MY_TRIGGER", line 8
    ORA-04088: error during execution of trigger 'STARS.MY_TRIGGER'
    how to solve this....?
    can anybody can explain solution for my problem with some good example please ?
    thanks

    Hi,
    From Documentation
    mutating table is a table that is currently being modified by an UPDATE, DELETE, or INSERT statement, or a table that might be updated by the effects of a DELETE CASCADE constraint.
    *The session that issued the triggering statement cannot query or modify a mutating table*. This restriction prevents a trigger from seeing an inconsistent set of data.
    This restriction applies to all triggers that use the FOR EACH ROW clause, and statement triggers that are fired as the result of a DELETE CASCADE
    To avoid..an article by tom kyte.
    http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936
    Hope it helps,
    CKLP                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

  • Mutating table exception on trigger with After Insert but not with before

    Hi
    I need to maintain some constraint on the table to have only one row for values of the columns but not by primary key constraint.
    Because in case of primary key the insert would fail and the rest of the operation would be discontinued, I cannot change in the somponent that inserts the row so I have to prevent that on the table I have.
    I created a before insert trigger on the table which checks if any row exists in the table with same column values as the one being inserted. if found I delete the rows and let the insert happen (w/o raising any error). if the rows do not exist then the insert shall be continued.
    I read at place that modifying the dame table in the trigger body shall raise a mutating table exception, but I donot get the exception when the trigger is fired.
    Just when I change the trigger to after insert trigger then the nutating table exception is thrown.
    Is it the right behavior i.e. the Before insert trigger does not raise the exception and only after insert does that, since I could not find the example for before insert triggers throwing such exception so I think it is better to confirm it before finalizing the implementation.
    Thanks
    Sapan

    sapan wrote:
    Hi Tubby
    I cannot user unique constraint because that would raise an exception upon violation and the third party component that is inserting in the table would fail.
    That component does some other tasks as well after this insert and if an exception is raised then those tasks would not be performed.
    Also I cannot change the component to ignore this exception.Well then, you're in a bit of a pickle.
    I'm guessing the trigger you have been working on isn't "safe". By that i mean that it doesn't account for multi-user scenarios. You'll need to serialize access to the data elements in question and implement some sort of locking mechanism to ensure that only 1 session can work with those values.
    After you work out how to do that it sounds as though you would be better served using an INSTEAD OF trigger (you'd need to implement this on a view which is made off of your base table).
    Here's one way you can work on serializing access to your table on a relatively fine grained level (as opposed to locking the entire table).
    Re: possible to lock stored procedure so only one session may run it at a time?
    Cheers,

  • Error "Mutating table" when execute a trigger

    Hi all,
    I'm a newbie in oracle. Recently i do some database migration from sql server 2005 to oracle 11g. Some of my table are using trigger which is not running in oracle. It has error "mutating table" when i'm trying to update some table. According to some information i got from the internet this can be solve by creating 1 packages and 3 trigger, but i found this article http://www.oracle.com/technetwork/issue-archive/2008/08-sep/o58asktom-101055.html which confuse me much. It says that the trigger is not allowed to be used for multiple user, meanwhile my application was for multiple user. What should i do then ?
    *sorry for my bad english                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

    Hi,
    Sorry for my late reply, below is one of my trigger that causes error. This trigger was automatically created when im doing the migration.
    create or replace
    TRIGGER "DBO_ORACLE_240312".tgrRwyPktUpd
    -- =============================================
    -- Author:          Debora Farah Rasul
    -- Create date: 09.02.2012
    -- Description:     Update Riwayat Pangkat untuk data SKCPNS/SKPNS
    -- =============================================
    AFTER UPDATE
    ON RiwayatPangkat
    FOR EACH ROW
    DECLARE
    v_temp NUMBER(1, 0) := 0;
    BEGIN
    IF NULL/*TODO:TRIGGER_NESTLEVEL()*/ > 2 THEN
    RETURN;
    END IF;
    --SQL Server BEGIN TRANSACTION;
    BEGIN
    SELECT 1 INTO v_temp
    FROM DUAL
    WHERE ( ( SELECT :NEW.isTrigger
    FROM DUAL ) = -1 );
    EXCEPTION
    WHEN OTHERS THEN
    NULL;
    END;
    IF v_temp = 1 THEN
    BEGIN
    MERGE INTO SKCPNS
    USING (SELECT :NEW.PegawaiID AS PegawaiID, :NEW.NoNota AS NoNota, :NEW.NoSK AS NoSK, :NEW.TglSK AS TglSK, :NEW.TMTPangkat AS TMTPangkat, :NEW.PangkatID AS PangkatID
    FROM dual) src
    ON (SKCPNS.PegawaiID = src.PegawaiID )
    WHEN MATCHED THEN UPDATE SET NoNota = src.NoNota,
    NoSK = src.NoSK,
    TglSK = src.TglSK,
    TMTCPNS = src.TMTPangkat,
    PangkatID = src.PangkatID;
    END;
    ELSE
    BEGIN
    SELECT 1 INTO v_temp
    FROM DUAL
    WHERE ( ( SELECT :NEW.isTrigger
    FROM DUAL ) = -2 );
    EXCEPTION
    WHEN OTHERS THEN
    NULL;
    END;
    IF v_temp = 1 THEN
    BEGIN
    MERGE INTO SKPNS
    USING (SELECT :NEW.PegawaiID AS PegawaiID, :NEW.NoSK AS NoSK, :NEW.TglSK AS TglSK, :NEW.TMTPangkat AS TMTPangkat, :NEW.PangkatID AS PangkatID
    FROM dual) src
    ON ( SKPNS.PegawaiID = src.PegawaiID )
    WHEN MATCHED THEN UPDATE SET NoSK = src.NoSK,
    TglSK = src.TglSK,
    TMTPNS = src.TMTPangkat,
    PangkatID = src.PangkatID;
    END;
    END IF;
    END IF;
    MERGE INTO RiwayatGaji
    USING (SELECT :NEW.PegawaiID AS PegawaiID, :NEW.NoUrut AS NoUrut, :NEW.NoSK AS NoSK, :NEW.TglSK AS TglSK, :NEW.TMTPangkat AS TMTPangkat, :NEW.PejabatPenetap AS PejabatPenetap, :NEW.MasaKerjaTh AS MasaKerjaTh, :NEW.MasaKerjaBl AS MasaKerjaBl, :NEW.PangkatID AS PangkatID, :NEW.JenisKP AS JenisKP
    FROM dual) src
    ON ( RiwayatGaji.PegawaiID = :NEW.PegawaiID
    AND RiwayatGaji.isTrigger = :NEW.NoUrut)
    WHEN MATCHED THEN UPDATE SET NoSK = src.NoSK,
    TglSK = src.TglSK,
    TMTSK = src.TMTPangkat,
    PejabatPenetap = src.PejabatPenetap,
    MasaKerjaTh = src.MasaKerjaTh,
    MasaKerjaBl = src.MasaKerjaBl,
    PangkatID = src.PangkatID,
    JenisKenaikan = src.JenisKP;
    END;
    *Btw thank u for the reply :)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

  • Mutating table exception & use of a table column in where clause

    Hello,
    I have a scenario in which I am getting a Mutating table exception in which I have a trigger using which I insert into a second table in case there is an insert in the first table or the one which is associated with the trigger .
    my trigger code has this line which is causing the Mutating table exception :
    BEGIN
    IF INSERTING THEN
    SELECT a,b INTO var_a,var_b
    FROM tableA,tableB,tableC
    WHERE tableC.c = :new:c
    The problem is the tableC reference in my where clause is causing a Mutating table exception , but I don't see any other way in which I can get rid of it cause I need to check if new:c values exists in the table or not , can anybody suggest how I can get rid of the tableC reference in my SQL statement yet be able to check for the value of :new:C in my statement ?

    Hopefully this demonstrates the problem , the bold portion or the where clause is where I am getting flummoxed , I need to be able to compare the new value to a column in table C but if I use tableC reference I get mutating table exception
    create or replace
    trigger myTrigger
    after insert or delete or update on TableC
    referencing old as old new as new
    for each row
    DECLARE val1 number; val2 CHAR(1);
    BEGIN
    IF INSERTING THEN
    SELECT tableA.val1,tableB.val2 INTO val1,val2
    FROM TableA tableA,TableB tableB
    WHERE :new.val1
    AND :new.val1 is not null
    AND tableA.val2 = :new.val2
    AND tableB.val3 = tableA.val3
    AND tableC.val4 = :new.val5
    INSERT INTO TableD (col1 ,
    col2,
    col3,
    col4,
    col5,
    col6,
    col7,
    col8,
    col9)
    VALUES(:new.val1,
    :new.val2,
    :new.val3,
    tableA.val1,
    tableB.val2,
    :new.val4,
    :new.val5,
    :new.val6,
    :new.val7);

  • MUTATING TABLES(ORA-04091) ERROR

    HI ALL,
    i am trying to solve the above problem. I don't have much experience in pl/sql. I tell u the problem.
    I am trying to write trigger on transaction_master table before insert or update so that record can insert into tran_modify_log table. Because of the referential integrity i got the error ORA-04091. I COPIED THE FOLLOWING CODE. BUT ITS FOR ONLY ONE COLUMN.OTHER COLUMNS ARE HARD CODED. U can see this in 2nd trigger IN_TRANS_MOD_LOG. can any body help me to insert all the column values from transaction_master table to tran_modify_log table. If is there any easy way please let me know.
    with regards,
    vali
    CREATE OR REPLACE PACKAGE INSERT_TRANSACTION_MODIFY_LOG IS
    -- DEFINE A PL/SQL TABLE TYPE TO STORE THE ORDER_ID INFO
    TYPE INSERT_TRAN_MOD_LOG_TABLE IS TABLE OF TRANSACTION_MASTER.TRANSACTION_ID%TYPE
    INDEX BY BINARY_INTEGER;
    -- DECLARE VARIABLES FOR THE PL/SQL TABLE AND COUNTER
    INSERT_TRAN_MOD_LOG_TABLE_REC INSERT_TRAN_MOD_LOG_TABLE;
    INS_T_M_L_TAB_INDEX_NUM PLS_INTEGER:=0;
    END INSERT_TRANSACTION_MODIFY_LOG;
    CREATE OR REPLACE TRIGGER INS_TRANS_MOD_LOG BEFORE INSERT OR UPDATE ON TRANSACTION_MASTER FOR EACH ROW
    BEGIN
    --INCREMENT PL/SQL TABLE INDEX BEFORE INSERTING
    INSERT_TRANSACTION_MODIFY_LOG.INS_T_M_L_TAB_INDEX_NUM:=INSERT_TRANSACTION_MODIFY_LOG.INS_T_M_L_TAB_INDEX_NUM+1;
    --ADD THE TRANSACTION_ID TO THE PL/SQL TABLE
    INSERT_TRANSACTION_MODIFY_LOG.INSERT_TRAN_MOD_LOG_TABLE_REC(INSERT_TRANSACTION_MODIFY_LOG.INS_T_M_L_TAB_INDEX_NUM):
    =NVL(:OLD.TRANSACTION_ID,:NEW.TRANSACTION_ID);
    END INS_TRANS_MOD_LOG;
    CREATE OR REPLACE TRIGGER IN_TRANS_MOD_LOG BEFORE INSERT OR UPDATE ON TRANSACTION_MASTER
    BEGIN
    -- LOOP THROUGH THE PL/SQL, PERFORMING PROCESSING FOR EACH TRANSACTION
    FOR LV_TAB_INDEX_NUM IN 1..INSERT_TRANSACTION_MODIFY_LOG.INS_T_M_L_TAB_INDEX_NUM LOOP
    -- INSERT INITIAL TRANSACTION RECORD FOR EVERY TRANSACTION
    INSERT INTO TRAN_MODIFY_LOG(MODIFY_DATE,MODIFY_TIME,TRANSACTION_ID,USER_ID)
    VALUES('13/06/2002','13:30',INSERT_TRANSACTION_MODIFY_LOG.INSERT_TRAN_MOD_LOG_TABLE_REC(LV_TAB_INDEX_NUM),'MIKE');
    END LOOP;
    -- INITIALIZE PACKAGE VARIABLE COUNTER FOR SUBSEQUENT INSERTS
    INSERT_TRANSACTION_MODIFY_LOG.INS_T_M_L_TAB_INDEX_NUM:=0;
    END IN_TRANS_MOD_LOG;
    /

    sorry, my mistake, point 7-8 became:
    7) But if u now login with the sys dba account:
    connect sys/dbapass@database
    then drop student.trg_a and student.trg_b and then recreate both under the sys schema:
    CREATE OR REPLACE TRIGGER SYS.TRG_A
    AFTER INSERT OR DELETE ON STUDENT.P
    FOR EACH ROW
    begin
    if deleting then
    update STUDENT.Q set cnt=cnt-1 where id=2;
    else
    update STUDENT.Q set cnt=cnt+1 where id=2;
    end if;
    end;
    /--- cut point for trigger creation
    CREATE OR REPLACE TRIGGER SYS.TRG_B
    AFTER INSERT OR UPDATE ON STUDENT.Q
    FOR EACH ROW
    declare
    p number;
    maxr number;
    begin
    select sum(CNT) into p from STUDENT.Q where id=:new.id;
    select sum(MAX) into maxr from STUDENT.R where id=:new.id;
    dbms_output.put_line('P:'||p||', maxr:'||maxr);
    if (p<=maxr) then
    dbms_output.put_line('p<=maxr is true');
    else
    dbms_output.put_line('p<=maxr is false');
    end if;
    end;
    8) reconnect with ur working user account:
    example: connect student/password@database
    9) when re-doing inserts as point 6), the trigger sys.trg_b will fire without raising any ora-04091 error!!!!
    The trigger behave like if the mutating table limitation is not existing at all!!!
    does anyone know anything about this behavior?
    thank u very much
    sincerely

  • How to solve mutating table error?

    I compiled the trigger below successfully:
    CREATE OR REPLACE TRIGGER avail_products
    BEFORE INSERT ON orders_tbl
    FOR EACH ROW
    DECLARE
    m_prodqty products_tbl.prod_qty%TYPE;
    m_ordered orders_tbl.ord_qty%TYPE;
    m_prodid orders_tbl.prod_id%TYPE;
    BEGIN
    SELECT p.prod_qty, o.ord_qty, o.prod_id
    INTO m_prodqty, m_ordered, m_prodid
    FROM products_tbl p, orders_tbl o
    WHERE ord_num=:NEW.ord_num;
    IF m_prodqty>=m_ordered THEN
    UPDATE products_tbl
    SET prod_qty=prod_qty-m_ordered
    WHERE prod_id=m_prodid;
    ELSE
    RAISE_APPLICATION_ERROR(-20101,'Product is not available');
    END IF;
    END;
    However, when I run my PL/SQL block as follows:
    DECLARE
    v_max NUMBER;
    BEGIN
    SELECT MAX(ord_num)+1
    INTO v_max
    FROM orders_tbl;
    INSERT INTO orders_tbl(ord_num, cust_id, prod_id, ord_qty, ord_date, dvy_date, refund)
    VALUES (v_max, &cust_id, &prod_id, &ord_qty, '&ord_date', '&dvy_date',0);
    COMMIT;
    END;
    UPDATE orders_tbl
    SET refund=0.1*(SELECT price FROM products_tbl WHERE prod_id=(SELECT prod_id FROM orders_tbl WHERE ord_num=(SELECT MAX(ord_num) FROM orders_tbl)))
    WHERE ord_num = (SELECT MAX(ord_num) FROM orders_tbl) AND dvy_date>ord_date+3;
    COMMIT;
    It gives me these errors:
    ERROR at line 1:
    ORA-01403: no data found
    ORA-01403: no data found
    ORA-06512: at "SYSTEM.AVAIL_PRODUCTS", line 9
    ORA-04088: error during execution of trigger 'SYSTEM.AVAIL_PRODUCTS'
    ORA-06512: at line 10
    I try to debug it again and again but still can't find the mistake. So I change the trigger option to AFTER INSERT, then I got the error message that the table is mutating and trigger migh not see it. Anyone know how to solve this problem?
    ERROR at line 2:
    ORA-04091: table SYSTEM.ORDERS_TBL is mutating, trigger/function may not see it
    ORA-06512: at "SYSTEM.AVAIL_PRODUCTS", line 13
    ORA-04088: error during execution of trigger 'SYSTEM.AVAIL_PRODUCTS'
    null

    This extract from an earlier post might be of help:
    You can solve this problem by using following thing
    1)create a view on same table with all fields
    and write trigger on table (insert,update or delete ) while inserting or updating or deleting row from table read from view.
    (Mutating error come when you are reading from one table and want to update,insert or delete row of same table).
    2)create a temporary table(but it is possible in 8i onword only) same as table on which you want to write trigger,while updating,inserting or deleting rows of table read from temporary table and after your work is over temporary table auotomatically drop (see proper command in oracle documentation to create temporary table).
    null

  • Solve mutating table error

    Hi,
    I want a solution for mutating table error. I am a newbie in oracle.
    I'll explain my scenario.
    There are two tables TEACHER and STUDENT
    both are linked using the field 'tid'. the foreign key relation is given as ON DELETE CASCADE
    so if i delete a row from teacher , the corresponding rows in student get deleted, but i want to back up all the students who comes under that teacher, who is getting deleted.
    I tried in TRIGGER, but getting mutating table error.
    Please help
    Thanks in advance
    Divya

    This extract from an earlier post might be of help:
    You can solve this problem by using following thing
    1)create a view on same table with all fields
    and write trigger on table (insert,update or delete ) while inserting or updating or deleting row from table read from view.
    (Mutating error come when you are reading from one table and want to update,insert or delete row of same table).
    2)create a temporary table(but it is possible in 8i onword only) same as table on which you want to write trigger,while updating,inserting or deleting rows of table read from temporary table and after your work is over temporary table auotomatically drop (see proper command in oracle documentation to create temporary table).
    null

  • Mutating table and recursive triggers

    Hello every one,
    I seem to be having a problem with a statement level update trigger. I want to use a trigger on a table then update the same table. Initially when I coded it as a row trigger but I received a ORA 04091 mutating error message.
    I refered a Oracle PL/SQL book and it suggested a work around. I recoded the trigger but it is not working. Oracle does not want to let me update the table I am running my statement level trigger(accompanied with a package and row level trigger) on. Please see code below. CREATE OR REPLACE PACKAGE service_guarantee_cap_data AS
    TYPE t_userid is table of bizguaranteereq.userid%type
    index by BINARY_INTEGER;
    TYPE t_recordid is table of bizguaranteereq.recordid%type
    index by BINARY_INTEGER;
    v_userid t_userid;
    v_recordid t_recordid;
    v_NumEntries BINARY_INTEGER :=0;
    end service_guarantee_cap_data;
    CREATE OR REPLACE TRIGGER service_guar_cap_row_update
    BEFORE UPDATE of statuscd ON bizguaranteereq
    FOR EACH ROW
    BEGIN
    service_guarantee_cap_data.v_NumEntries := service_guarantee_cap_data.v_NumEntries + 1;
    service_guarantee_cap_data.v_userid(service_guarantee_cap_data.v_NumEntries ):= :new.userid;
    service_guarantee_cap_data.v_recordid(service_guarantee_cap_data.v_NumEntries ) := :new.recordid;
    END service_guar_cap_row_update;
    CREATE OR REPLACE TRIGGER service_guar_cap_stat_update
    after UPDATE of statuscd ON bizguaranteereq
    DECLARE
    v_rowid_2 number;
    v_userid_2 number;
    v_recordid_2 number;
    v_overcap_99 number;
    BEGIN
    v_0 := 0;
    v_overcap_99 := 99;
    FOR v_loopindex in 1..service_guarantee_cap_data.v_NumEntries LOOP
    v_userid_2 := service_guarantee_cap_data.v_userid(v_loopindex);
    v_recordid_2 := service_guarantee_cap_data.v_recordid(v_loopindex);
    select count(*)
    into v_statuscd_count
    from bizguaranteereq
    where userid=v_userid_2
    and statuscd=99;
    IF v_statuscd_count > 0
    THEN
    update bizguaranteereq
    set statuscd=v_overcap_99
    where userid = v_userid_2
    and recordid=v_recordid_2;
    END IF;
    END LOOP;
    service_guarantee_cap_data.v_NumEntries := v_0;
    END service_guar_cap_stat_update;

    I did not receive a mutating error with my work around code. I think the problem lies with the update DML. I will try your suggestion of an external proceedure that takes the parameter given from the statment level trigger and then updates the table using the proceedure.
    Thanks
    <BLOCKQUOTE><font size="1" face="Verdana, Arial, Helvetica">quote:</font><HR>Originally posted by wasim hamwi ([email protected]):
    I am not sure this code will work, you will get mutating table because you are selecting the count(*) from the sam table you are tying to update....use Autonomous_transaction if your Db iv V8.1.5 or higher.
    Wasim<HR></BLOCKQUOTE>
    null

Maybe you are looking for