Mutating error : row level BEFORE UPDATE trigger

Hi,
I had an issue on mutating terror(was trying to write a row level BEFORE update trigger), however i got it resolved after refering tom kytes web site. I thought i would share it with everyone, might be helpful for a few... Thanks!
I will be more than happy to learn on further better ways of resolving this issue.
Below I have posted the trigger that was causing this error and the work around for that issue, I created a package and three other triggers to replace row level BEFORE update trigger:
++trigger that was causing this issue:++
CREATE OR REPLACE TRIGGER C_F_BI
BEFORE INSERT ON CONTACT_FUNCTION FOR EACH ROW
declare
cursor function_code_cur ( cur_contact_id CONTACT.Contact_Id%type,
cur_function_type_code CONTACT_FUNCTION.Function_Type_Code%type)
is
select
cft.function_type_code,
cft.multiples_permitted
from
CONTACT_FUNCTION cf,
CONTACT c,
CONTACT_FUNCTION_TYPE cft
where
c.acct_id = (select acct_id from contact where contact_id = cur_contact_id)
and c.contact_id = cf.contact_id
and cf.function_type_code = cft.function_type_code
and cft.function_type_code = cur_function_type_code;
v_function_type_code contact_function_type.function_type_code%type;
v_multiples_permitted contact_function_type.multiples_permitted%type;
E_Multiples_Not_Permitted Exception;
begin
if not function_code_cur%isopen then
open function_code_cur(:new.contact_Id,:new.function_type_code);
end if;
loop
fetch function_code_cur into v_function_type_code, v_multiples_permitted;
exit when not function_code_cur%found;
end loop;
** if the fetch returns a v_multiples_permitted of 'Y' or no record is found, then it is
** ok to add the record. Otherwise raise an error because that function_type is already
** being used at the current acct.
if v_multiples_permitted = 'N' then
raise E_Multiples_Not_Permitted;
end if;
close function_code_cur;
EXCEPTION
when E_Multiples_Not_Permitted then
raise_application_error( -20001,'Multiples not allowed for function type ' ||
v_function_type_code || '. sqlerrm - ' || sqlerrm );
when others then
raise;
end;
++solution for above issue :++
create or replace package state_pkg
is
type ridArray_rec is record(rid rowid, cont_id number, cont_fn_type varchar2(20));
type ridArray is table of ridArray_rec index by binary_integer;
newRows ridArray;
empty ridArray;
end state_pkg;
create or replace trigger contact_function_bu1
before update on contact_function
begin
state_pkg.newRows := state_pkg.empty;
end;
create or replace trigger contact_function_bu2
before update ON CONTACT_FUNCTION FOR EACH ROW
DECLARE
I NUMBER:=0;
begin
I := state_pkg.newRows.count+1;
state_pkg.newRows( I ).rid := :new.rowid;
state_pkg.newRows( I ).cont_id := :new.contact_id;
state_pkg.newRows( I ).cont_fn_type := :new.function_type_code;
end;
create or replace trigger contact_function_bu
after update ON CONTACT_FUNCTION
declare
cursor function_code_cur ( cur_contact_id CONTACT.Contact_Id%type,
cur_function_type_code CONTACT_FUNCTION.Function_Type_Code%type,
rid2 rowid)
is
select
cft.function_type_code,
cft.multiples_permitted
from
CONTACT_FUNCTION cf,
CONTACT c,
CONTACT_FUNCTION_TYPE cft
where
c.acct_id = (select acct_id from contact where contact_id = cur_contact_id)
and c.contact_id = cf.contact_id
and cf.function_type_code = cft.function_type_code
and cft.function_type_code = cur_function_type_code
and cf.rowid = rid2;
v_function_type_code contact_function_type.function_type_code%type;
v_multiples_permitted contact_function_type.multiples_permitted%type;
E_Multiples_Not_Permitted Exception;
begin
for i in 1 .. state_pkg.newRows.count loop
if not function_code_cur%isopen then
open function_code_cur(state_pkg.newRows(i).cont_id, state_pkg.newRows(i).cont_fn_type, state_pkg.newRows(i).rid);
end if;
loop
fetch function_code_cur into v_function_type_code, v_multiples_permitted;
exit when not function_code_cur%found;
end loop;
** if the fetch returns a v_multiples_permitted of 'Y' or no record is found, then it is
** ok to add the record. Otherwise raise an error because that function_type is already
** being used at the current acct.
if v_multiples_permitted = 'N' then
raise E_Multiples_Not_Permitted;
end if;
close function_code_cur;
end loop;
EXCEPTION
when E_Multiples_Not_Permitted then
raise_application_error( -20001,'Multiples not allowed for function type ' ||
v_function_type_code || '. sqlerrm - ' || sqlerrm );
when others then
raise;
end;
/

It seems you could have solved the issue otherwise:
CREATE OR REPLACE TRIGGER c_f_bi
   BEFORE INSERT
   ON contact_function
   FOR EACH ROW
DECLARE
   v_function_type_code        contact_function_type.function_type_code%TYPE;
   v_multiples_permitted       contact_function_type.multiples_permitted%TYPE;
   e_multiples_not_permitted   EXCEPTION;
BEGIN
   BEGIN
      SELECT cft.function_type_code, cft.multiples_permitted
        INTO v_function_type_code, v_multiples_permitted
        FROM contact c, contact_function_type cft
       WHERE c.acct_id = (SELECT acct_id
                            FROM contact
                           WHERE contact_id = :NEW.contact_id)
         AND c.contact_id = :NEW.contact_id
         AND cft.function_type_code = :NEW.function_type_code;
   EXCEPTION
      WHEN NO_DATA_FOUND
      THEN
         v_function_type_code := :NEW.function_type_code;
         v_multiples_permitted := '?';
   END;
** if the query returns a v_multiples_permitted of 'Y' or no record is found, then it is
** ok to add the record. Otherwise raise an error because that function_type is already
** being used at the current acct.
   IF v_multiples_permitted = 'N'
   THEN
      RAISE e_multiples_not_permitted;
   END IF;
EXCEPTION
   WHEN e_multiples_not_permitted
   THEN
      raise_application_error (-20001,
                                  'Multiples not allowed for function type '
                               || v_function_type_code
                               || '. sqlerrm - '
                               || SQLERRM
   WHEN OTHERS
   THEN
      RAISE;
END;
/:p

Similar Messages

  • How to avoid mutating error when insert or update record

    Hi ,
    I have one transaction table which is having some detail record under one transaction number, after the one transaction number is over by insert or update, i
    want to check the total amounts of one flag should be matched on same table if it is not then give error message. But i am getting mutating error on insert or update event trigger on statement level trigger on above table.
    Is there any other way to avoid mutating error to solve the above problem or some temp table concepts to be used. help me its urgent.
    Thanks in advance,
    Sachin Khaladkar
    Pune

    Sachin, here's as short of an example as I could come up with on the fly. The sample data is ficticious and for example only.
    Let's say I need to keep a table of items by category and my business rule states that the items in the table within each category must total to 100% at all times. So I want to insert rows and then make sure any category added sums to 100% or I will rollback the transation. I can't sum the rows in a row-level trigger because I'd have to query the table and it is mutating (in the middle of being changed by a transaction). Even if I could query it while it is mutating, there may be multiple rows in a category with not all yet inserted, so checking the sum after each row is not useful.
    So here I will create;
    1. the item table
    2. a package to hold my record collection (associative array) for the trigger code (the category is used as a key to the array; if I insert 3 rows for a given category, I only need to sum that category once, right?
    3. a before statement trigger to initialize the record collection (since package variables hang around for the entire database session, I need to clear the array before the start of every DML (INSERT in this case) statement against the item table)
    4. a before row trigger to collect categories being inserted
    5. an after statement trigger to validate my business rule
    I then insert some sample data so you can see how it works. Let me know if you have any questions about this.
    SQL> CREATE TABLE item_t
      2   (category  NUMBER(2)   NOT NULL
      3   ,item_code VARCHAR2(2) NOT NULL
      4   ,pct       NUMBER(3,2) NOT NULL);
    Table created.
    SQL>
    SQL> CREATE OR REPLACE PACKAGE trg_pkg IS
      2    TYPE t_item_typ IS TABLE OF item_t.category%TYPE
      3      INDEX BY PLS_INTEGER;
      4    t_item       t_item_typ;
      5    t_empty_item t_item_typ;
      6  END trg_pkg;
      7  /
    Package created.
    SQL> SHOW ERRORS;
    No errors.
    SQL>
    SQL> CREATE OR REPLACE TRIGGER item_bs_trg
      2    BEFORE INSERT
      3    ON item_t
      4  BEGIN
      5    DBMS_OUTPUT.put_line('Initializing...');
      6    trg_pkg.t_item := trg_pkg.t_empty_item;
      7  END item_bs_trg;
      8  /
    Trigger created.
    SQL> SHOW ERRORS;
    No errors.
    SQL>
    SQL> CREATE OR REPLACE TRIGGER item_br_trg
      2    BEFORE INSERT
      3    ON item_t
      4    FOR EACH ROW
      5  BEGIN
      6    trg_pkg.t_item(:NEW.category) := :NEW.category;
      7    DBMS_OUTPUT.put_line('Inserted Item for Category: '||:NEW.category);
      8  END item_br_trg;
      9  /
    Trigger created.
    SQL> SHOW ERRORS;
    No errors.
    SQL>
    SQL> CREATE OR REPLACE TRIGGER item_as_trg
      2    AFTER INSERT
      3    ON item_t
      4  DECLARE
      5    CURSOR c_item (cp_category item_t.category%TYPE) IS
      6      SELECT SUM(pct) pct
      7        FROM item_t
      8       WHERE category = cp_category;
      9  BEGIN
    10    DBMS_OUTPUT.put_line('Verifying...');
    11    FOR i IN trg_pkg.t_item.FIRST..trg_pkg.t_item.LAST LOOP
    12      DBMS_OUTPUT.put_line('Checking Category: '||trg_pkg.t_item(i));
    13      FOR rec IN c_item(trg_pkg.t_item(i)) LOOP
    14        IF rec.pct != 1 THEN
    15          RAISE_APPLICATION_ERROR(-20001,'Category '||trg_pkg.t_item(i)||' total = '||rec.pct);
    16        END IF;
    17      END LOOP;
    18    END LOOP;
    19  END item_as_trg;
    20  /
    Trigger created.
    SQL> SHOW ERRORS;
    No errors.
    SQL> INSERT INTO item_t
      2    SELECT 1, 'AA', .3 FROM DUAL
      3    UNION ALL
      4    SELECT 2, 'AB', .6 FROM DUAL
      5    UNION ALL
      6    SELECT 1, 'AC', .2 FROM DUAL
      7    UNION ALL
      8    SELECT 3, 'AA',  1 FROM DUAL
      9    UNION ALL
    10    SELECT 1, 'AA', .5 FROM DUAL
    11    UNION ALL
    12    SELECT 2, 'AB', .4 FROM DUAL;
    Initializing...
    Inserted Item for Category: 1
    Inserted Item for Category: 2
    Inserted Item for Category: 1
    Inserted Item for Category: 3
    Inserted Item for Category: 1
    Inserted Item for Category: 2
    Verifying...
    Checking Category: 1
    Checking Category: 2
    Checking Category: 3
    6 rows created.
    SQL>
    SQL> SELECT * FROM item_t ORDER BY category, item_code, pct;
      CATEGORY IT        PCT
             1 AA         .3
             1 AA         .5
             1 AC         .2
             2 AB         .4
             2 AB         .6
             3 AA          1
    6 rows selected.
    SQL>
    SQL> INSERT INTO item_t
      2    SELECT 4, 'AB', .5 FROM DUAL
      3    UNION ALL
      4    SELECT 5, 'AC', .2 FROM DUAL
      5    UNION ALL
      6    SELECT 5, 'AA', .5 FROM DUAL
      7    UNION ALL
      8    SELECT 4, 'AB', .5 FROM DUAL
      9    UNION ALL
    10    SELECT 4, 'AC', .4 FROM DUAL;
    Initializing...
    Inserted Item for Category: 4
    Inserted Item for Category: 5
    Inserted Item for Category: 5
    Inserted Item for Category: 4
    Inserted Item for Category: 4
    Verifying...
    Checking Category: 4
    INSERT INTO item_t
    ERROR at line 1:
    ORA-20001: Category 4 total = 1.4
    ORA-06512: at "PNOSKO.ITEM_AS_TRG", line 12
    ORA-04088: error during execution of trigger 'PNOSKO.ITEM_AS_TRG'
    SQL>
    SQL> SELECT * FROM item_t ORDER BY category, item_code, pct;
      CATEGORY IT        PCT
             1 AA         .3
             1 AA         .5
             1 AC         .2
             2 AB         .4
             2 AB         .6
             3 AA          1
    6 rows selected.
    SQL>

  • BEFORE UPDATE Trigger

    Hi,
    I'm looking for a solution to find out which columns are set in the update-statement inside a before update trigger. Can someone give me a hint?!
    What I want to do:
    I want to ensure that an update-statement for a special table always include attribute "XXX". To declare this attribute as "not null" is useless, because it is set correctly at insert. To compare the new value against the old value in a before update trigger isn't possible because the new value can be the same as the old value.
    I'm using Oracle 8i.

    There is no need to use two triggers and a temporary table where a simple insert from the before trigger will do the job.
    You can just insert the :old.column values straigth into a history table within the before update trigger though I would prefer to use an after update trigger. Nevertheless, both the insert into history and the update will be part of one transaction so the two action will commit or rollback together:
    UT1 > create or replace trigger marktest_bu
    2 before update on marktest
    3 for each row
    4 begin
    5 insert into marktest_hist
    6 values (:old.fld1, :old.fld2, :old.fld3, :old.fld4);
    7 end;
    8 /
    Trigger created.
    UT1 > select * from marktest_hist;
    no rows selected
    UT1 > update marktest set fld1 = 'trigtest2'
    2 where fld1 = 'trigtest';
    1 row updated.
    UT1 > select * from marktest_hist;
    FLD1 FLD2 FLD3 FLD4
    trigtest 9 28-MAY-04 trigtest
    IMHO -- Mark D Powell --

  • Slow update on 11g in conjuction with before update trigger

    Hello,
    I have strange problem - when on table exists before update trigger(in its body is nothing important, maybe problem is on other triggers aswell), then repeating update on this table is slower and slower on 11g, on 10g it is ok. Problem is on windows and linux platform aswell.
    I created some scripts to simulate this behavior, in table is 60 000 row. In one loop I update all 60 000 rows from table and measure time.
    Can someone tell me where problem is and if it is possible to manage it with some settings or anyway ? In our application it is big problem, similar operation takes days ......
    thanks tomas
    times for 10g:
    Trigger disabled
    Loop 1 - 6,13 secs
    Loop 2 - 2,92 secs
    Loop 3 - 3,19 secs
    Loop 4 - 2,95 secs
    Loop 5 - 3,39 secs
    Trigger enabled
    Loop 1 - 4,83 secs
    Loop 2 - 3,78 secs
    Loop 3 - 4,75 secs
    Loop 4 - 3,91 secs
    Loop 5 - 3,81 secs
    times for 11g:
    Trigger disabled
    Loop 1 - 2,27 secs
    Loop 2 - 2,4 secs
    Loop 3 - 2,3 secs
    Loop 4 - 2,42 secs
    Loop 5 - 2,36 secs
    Trigger enabled
    Loop 1 - 8,01 secs
    Loop 2 - 17,22 secs
    Loop 3 - 29,21 secs
    Loop 4 - 58,43 secs
    Loop 5 - 115,59 secs
    script for create test table
    CREATE TABLE SD3Test
       (MPID INTEGER NOT NULL ENABLE,
    ROWCOUNT NUMBER(10,0),
    CLOSEDROWCOUNT NUMBER(10,0),
    AMOUNT NUMBER(18,2) DEFAULT 0 NOT NULL ENABLE,
    LOCALAMOUNT NUMBER(18,2) DEFAULT 0 NOT NULL ENABLE,
    CLOSED CHAR(1 BYTE) DEFAULT 'N' NOT NULL ENABLE);
    ALTER TABLE SD3Test ADD CONSTRAINT SD3TestPK PRIMARY KEY (MPID);
    --fill test data
    DECLARE mCnt INTEGER;
    BEGIN
    mCnt := 0;
    FOR mCnt IN 1..60000 loop
      INSERT INTO SD3Test (MPID, Amount, LocalAmount, RowCount, ClosedRowCount)
      VALUES(mCnt, 0, 0, 0, 0);
    END loop;
    END;
    --create trigger
    CREATE OR REPLACE TRIGGER SD3TestAU
      BEFORE UPDATE ON SD3Test FOR EACH ROW
    DECLARE
    mInt INTEGER;
    BEGIN
      /*original code of our trigger, but performance problem is
    not depend on it, just depend on existence of this trigger
    IF ((:new.RowCount=:new.ClosedRowCount) and (:new.RowCount>0)) THEN
      :new.Closed:='A';
    ELSE
      :new.Closed:='N';
    end if;
    mInt := 1;
    END;
    / script for run test
    --test for updates with trigger disabled and enabled
    set serveroutput on;
    DECLARE
      mCnt INTEGER;
      mLoop INTEGER;
      mDisEna INTEGER;
      mStart NUMBER;
      mStop NUMBER;
    BEGIN
    --2 loops - first with disabled trigger, second with enabled trigger
    FOR mDisEna IN 1..2 loop
      IF mDisEna = 1 THEN
       execute immediate 'ALTER TRIGGER SD3TestAU disable';
       dbms_output.put_line('Trigger disabled');
      ELSE
       execute immediate 'ALTER TRIGGER SD3TestAU enable';
       dbms_output.put_line('Trigger enabled');
      END IF;
      -- 3 inner loops for measure time
      FOR mLoop IN 1..3 loop
        --update on all records in table
       mStart := dbms_utility.get_time;
       FOR mCnt IN 1..60000 loop
        UPDATE SD3Test
         SET
        ROWCOUNT = ROWCOUNT+1,
        CLOSEDROWCOUNT = CLOSEDROWCOUNT+1,
        AMOUNT = AMOUNT + mCnt,
        LOCALAMOUNT = LOCALAMOUNT + mCnt
        WHERE
         MPID = mCnt;
       END loop;
       mStop := dbms_utility.get_time;
       dbms_output.put_line('Loop ' || mLoop || ' - ' || round((mStop - mStart)/100,2) || ' secs');
      END loop;
    END loop;
    END;
    /

    Hello,
    Your case has been reported as a bug #7173924 (TRIGGER IS MUCH SLOWER IN 11G) few days ago.
    Still on analyze.
    Nicolas.

  • Before Update Trigger has mutating problem

    I'm getting a mutating problem with this updating trigger. I'm not sure how to deal with it. Here is my code:
    CREATE OR REPLACE TRIGGER WTL_SMP_TRG2
    BEFORE UPDATE ON WTL_SAMPLES
    FOR EACH ROW
    DECLARE
         sampleCount NUMBER(1) := 0;
         dupLabSampleID NUMBER(8) := 0;
    BEGIN
         SELECT COUNT(sample_ID)
         INTO sampleCount
         FROM wtl_samples
    WHERE jb_job_id = :new.jb_job_id
    AND lab_no = :new.lab_no
         AND sample_ID != :old.sample_ID;
         IF sampleCount > 0 THEN
         SELECT sample_ID
         INTO dupLabSampleID
         FROM wtl_samples
         WHERE jb_job_id = :new.jb_job_id
         AND lab_no = :new.lab_no
              AND sample_ID != :old.sample_ID;
    RAISE_APPLICATION_ERROR(-20501, 'Update failed, Lab Number ' || :new.lab_no || ' is used by SampleID: ' || dupLabSampleID);
    END IF;
    --EXCEPTION
    --     WHEN OTHERS THEN
    -- RAISE_APPLICATION_ERROR(-20901, 'Error in WTL_SMP_TRG2.');
    END WTL_SMP_TRG2;
    any help appreciated
    adam

    I guess I couldve done that, but was using design editor and didn't know how to put a unique constraint in. Is the problem only because I'm referencing the :old.sample_ID, or the :new values as well? If it's just the :old value I could write a before update statement trigger to place the sample_id into a package varaible and then call that variable up in the row level trigger.... i've tried this, but don't know how to pull the sample_id value i need in the before statement trigger... i'll supply the code i've done so far...
    CREATE OR REPLACE TRIGGER WTL_SMP_TRG2_INIT
    BEFORE UPDATE ON WTL_SAMPLES
    DECLARE
    BEGIN
         wtl_trg_custom_pkg.oldSampleID := sample_id; /* Doesn't know sample_id...? */
    END WTL_SMP_TRG2_INIT;

  • Before Update Trigger compilation problem

    Hello experts! I have a compilation problem for a trigger I am trying to create.
    As a matter of fact it should update INT_INITIAL with the old value of INT_LOCK.
    The compilation fails and the debugger raises an ORA 01747 error (invalid declaration for user table, user column etc.)
    Do you have an idea what is wrong with my code?
    create or replace
    TRIGGER TRIGGER_INT_INITIAL
    BEFORE UPDATE ON  TBL_MATRIX_INTERMEDIATE_RESULT
    FOR EACH ROW
    Begin
      IF NVL(:new.INT_INITIAL, 0) != :old.INT_LOCK THEN
           UPDATE TBL_MATRIX_INTERMEDIATE_RESULT set
          :NEW.INT_INITIAL = :old.INT_LOCK;
      END IF;
    END;Regards,
    Seb

    Hi Seb,
    You don't need to use UPDATE stmt here as you are updating the same table on which your trigger is fired. So it may cause mutating table error too.
    when you use :new.colname it will immediately take care of the new value to be inserted in the respective column.
    So no need to write Update stmt.
    Hence remove,
    UPDATE TBL_MATRIX_INTERMEDIATE_RESULT set And use := is an assignment operator whereas = is to equate..
    :=Twinkle

  • Halting the update from a BEFORE UPDATE trigger

    Hello,
    I'm writing a trigger which is set to fire before update. One of the possible scenarios requires that the row being updated is not updated but instead deleted. Is it possible to send a DELETE query and then stop the update process so it doesn't spit out an error? I haven't tested this yet, but I'm quite sure it will give an error if it's trying to update a row which has just been deleted.
    Thanks,
    Pavel

    Hi,
    Personally, I don't like implement some business logic into trigger... so, why run an update whenever you need a delete ?
    I would modify the original code to delete in this case instead of update.
    My 2 cents,
    Nicolas.
    SQL> create table pavel (id number, txt varchar2(10));
    Table created.
    SQL> insert into pavel values (1, 'This one');
    1 row created.
    SQL> ed
    Wrote file afiedt.buf
      1  create or replace trigger pavel_trg
      2  before update on pavel
      3  for each row
      4  begin
      5  delete from pavel where id = :old.id;
      6* end;
    SQL> /
    Trigger created.
    SQL> update pavel set txt = 'Two';
    update pavel set txt = 'Two'
    ERROR at line 1:
    ORA-04091: table SCOTT.PAVEL is mutating, trigger/function may not see it
    ORA-06512: at "SCOTT.PAVEL_TRG", line 2
    ORA-04088: error during execution of trigger 'SCOTT.PAVEL_TRG'Message was edited by:
    N. Gasparotto

  • Help discovering what's wrong w/ my before update trigger

    Let me prefix this w/ the fact that I'm an idiot, so be kind.
    I have one trigger that is not working (seemingly), and I am about googled out so I thought I'd ask and see if anyone couldn't provide thoughts, insults, suggestions or what have you.
    Database being used is 10g XE and updates are being done transactionally.
    I have a table that stores (among other things) the status of a particular type of (app specific) transaction. When that status changes to a particular value, I have a trigger that updates another table with the date that this status change took place.
    <pre>Table: XTransaction
    id (pk)
    statusid (int)
    ...</pre>
    and here is what my trigger looks like:
    <pre>create or replace trigger x_transaction_update before update on xtransaction
    for each row
    declare
    begin
    if( :old.statusid = 1) then -- this is here because I got an error when I tried to use a when clause above
    begin
    -- I log before the update w/ some other info to tell whether I've been to this spot or not
    update sometable set when_it_happened = sysdate where xtransid = :old.id;
    -- I log after the update too
    exception
    when others then
    -- I log sqlerrm
    end;
    end;
    end if;
    end;</pre>
    here's what I've been able to gather through testing & viewing logs from the trigger:
    1. there's no exception being logged,
    2. the pre/post update logs with all the correct data (proving that the trigger is fired),
    3. when I update xtransaction from visual studio (through the oracle addin which lets you run queries against the database), the status is changed, the trigger is fired, and the other table is updated.
    4. when the application that normally updates the xtransaction table runs, xtransaction is updated, the trigger is fired, and sometable is not updated.
    so I have absolutely no clue where to go with this one. Usually I could fire up sql server's query analyser and watch what's coming through, and I've tried to use toad's commercial tool to do this, but to no avail. I've tried changing it to an after update, but had the same results. I wrote this some months ago, and it was working then, but not now.

    MadHatter wrote:
    @Centinul
    the only difference between what I posted and the actual trigger are table / column names, and a sproc I wrote for the logging in place of the comments I have:
    log_msg('update sometable set arrival = sysdate where transid = ' || :old.id);I know this doesn't answer the question you have now, you should seriously consider removing the WHEN OTHERS clause altogether OR ensure that there is a RAISE or RAISE_APPLICATION_ERROR there.
    This trigger isn't syntactically correct either:
    create or replace trigger x_transaction_update before update on xtransaction
    for each row
    declare
    begin
        if( :old.statusid = 1) then -- this is here because I got an error when I tried to use a when clause above
            begin
                -- I log before the update w/ some other info to tell whether I've been to this spot or not
                update sometable set when_it_happened = sysdate where xtransid = :old.id;
                -- I log after the update too
            exception
                when others then
                    -- I log sqlerrm
                end;
            end; /* Extra END here.... */
        end if;
    end;Edited by: Centinul on Oct 30, 2009 1:23 PM

  • Before update trigger on a view

    Hello,
    is not possible to write a before update or insert trigger based on a view?
    create or replace trigger trg_bef_upd_vwangajatiabsente
    before update on vw_angajati_absente
    referencing old as old new as new
    for each row
    begin
    if :old.motivabila='N' and :new.motivabila='D' then raise_application_error(-20433, 'Nu se poate modifica o absenta nemotivabila!');
    end;is it possible to solve these situations? :)
    Regards,

    Roger22 wrote:
    regarding to 2)
    in my trigger i must raise_application_error? if i don't raise then i need to issue update statements..... ?If you have an INSTEAD OF trigger that just has a body similar to the body you posted above, that would mean that update statements either
    - Raise an error
    - Do nothing (i.e. do not update any data in any table)
    That is a syntactically valid state-- Oracle will certainly allow you to have an INSTEAD OF UPDATE trigger that effectively throws away update statements. It's just that it would be rather rare that this would be the desired behavior. Presumably, if you're going through the effort of writing the trigger, you want certain update statements to succeed and, thus, to update data. If that is the case, your trigger would have to have UPDATE statements that update the proper row(s) in the proper base table(s).
    An INSTEAD OF UPDATE trigger is literally that. You are replacing, in its entirety, the update statement against the view with the code in your trigger. So your trigger would need to issue the base table updates that Oracle would have had there not been a trigger on the view.
    Justin

  • After/before update trigger

    Hi All
    Does any onoe know
    what 's the difference between after update/insert trigger and before update/insert trigger
    on database tables.

    Hi
    The basic diffrence is
    Before Update triggers before the table is updated and
    After update triggers after the table is updated but
    before the implicit commit fires.
    therefore when you raise the application error a
    implicit Rollback happens and the record is not commited.
    Regards
    Shajesh Nair
    Deloitte.
    [email protected]

  • Error while using Before report trigger. -- Urgent

    Dear All,
    The following error I am getting when I execute my data template where I have used Before Report Trigger. I am also pasting the Data Template that I have developed.
    ============================
    Error
    ============================
    XDO Data Engine Version No: 5.6.3
    Resp: 20560
    Org ID : 204
    Request ID: 4846248
    All Parameters: P_LOB=01:P_DIV_FROM=:P_DIV_TO=:P_FROM_ORG=:P_TO_ORG=:P_INV_FROM=:P_TO_INV=:P_TRX_DATE_FROM="2003/01/01 00:00:00":P_TRX_DATE_TO="2003/01/15 00:00:00"
    Data Template Code: SSBWIPANA_MFGR
    Data Template Application Short Name: WIP
    Debug Flag: N
    {P_DIV_FROM=, P_TRX_DATE_TO=2003/01/15 00:00:00, P_DIV_TO=, P_FROM_ORG=, P_TO_ORG=, P_TRX_DATE_FROM=2003/01/01 00:00:00, P_INV_FROM=, P_LOB=01, P_TO_INV=}
    Calling XDO Data Engine...
    [122407_011745100][][EXCEPTION] SQLException encounter while executing data trigger....
    java.sql.SQLException: ORA-06550: line 2, column 12:
    PLS-00302: component 'P_LOB' must be declared
    ORA-06550: line 2, column 1:
    PL/SQL: Statement ignored
    ORA-06550: line 3, column 12:
    PLS-00302: component 'P_DIV_FROM' must be declared
    ORA-06550: line 3, column 1:
    PL/SQL: Statement ignored
    ORA-06550: line 4, column 12:
    PLS-00302: component 'P_DIV_TO' must be declared
    ORA-06550: line 4, column 1:
    PL/SQL: Statement ignored
    ORA-06550: line 5, column 12:
    PLS-00302: component 'P_FROM_ORG' must be declared
    ORA-06550: line 5, column 1:
    PL/SQL: Statement ignored
    ORA-06550: line 6, column 12:
    PLS-00302: component 'P_TO_ORG' must be declared
    ORA-06550: line 6, column 1:
    PL/SQL: Statement ignored
    ORA-06550: line 7, column 12:
    PLS-00302: component 'P_FROM_INV' must be declared
    ORA-06550: line 7, column 1:
    PL/SQL: Statement ignored
    ORA-06550: line 8, column 12:
    PLS-00302: component 'P_TO_INV' must be declared
    ORA-06550: line 8, column 1:
    PL/SQL: Statement ignored
         at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
         at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
         at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
         at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
         at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:215)
         at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:967)
         at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168)
         at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3327)
         at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3433)
         at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:4394)
         at oracle.apps.xdo.dataengine.XMLPGEN.executeTriggers(XMLPGEN.java:699)
         at oracle.apps.xdo.dataengine.XMLPGEN.processData(XMLPGEN.java:254)
         at oracle.apps.xdo.dataengine.XMLPGEN.processXML(XMLPGEN.java:205)
         at oracle.apps.xdo.dataengine.XMLPGEN.writeXML(XMLPGEN.java:237)
         at oracle.apps.xdo.dataengine.DataProcessor.processData(DataProcessor.java:364)
         at oracle.apps.xdo.oa.util.DataTemplate.processData(DataTemplate.java:236)
         at oracle.apps.xdo.oa.cp.JCP4XDODataEngine.runProgram(JCP4XDODataEngine.java:293)
         at oracle.apps.fnd.cp.request.Run.main(Run.java:157)
    =====================================================
    Data Template
    ====================================================
    <dataTemplate name="SSBWIPANA_MFGR" defaultPackage="PRODUCTION" version="1.0">
    <parameters>
    <parameter name="P_LOB" datatype="charecter"/>
    <parameter name="P_DIV_FROM" datatype="charecter"/>
    <parameter name="P_DIV_TO" datatype="charecter"/>
    <parameter name="P_FROM_ORG" datatype="charecter"/>
    <parameter name="P_TO_ORG" datatype="charecter"/>
    <parameter name="P_FROM_INV" datatype="charecter"/>
    <parameter name="P_TO_INV" datatype="charecter"/>
    <parameter name="P_TRX_DATE_FROM" datatype="charecter"/>
    <parameter name="P_TRX_DATE_TO" datatype="charecter"/>
    </parameters>
    <dataQuery>
    <sqlStatement name="Q_1">
    <![CDATA[SELECT DISTINCT MSI.CONCATENATED_SEGMENTS, MMT.INVENTORY_ITEM_ID,
                    MSI.DESCRIPTION, MMT.TRANSACTION_UOM, SDT.TRX_DATE,
                    MTP.ORGANIZATION_CODE, MMT.ORGANIZATION_ID
               FROM MTL_MATERIAL_TRANSACTIONS MMT,
                    MTL_PARAMETERS MTP,
                    MTL_SYSTEM_ITEMS_VL MSI,
                    SSBWIP_DATE_TEMP SDT
              WHERE MMT.INVENTORY_ITEM_ID = MSI.INVENTORY_ITEM_ID
                AND MMT.ORGANIZATION_ID = MSI.ORGANIZATION_ID
                AND MSI.ORGANIZATION_ID = MTP.ORGANIZATION_ID
                AND MMT.ORGANIZATION_ID = MTP.ORGANIZATION_ID
                AND MMT.TRANSACTION_TYPE_ID IN (17, 44)
                AND MMT.ORGANIZATION_ID IN (
                       SELECT MP.ORGANIZATION_ID
                         FROM MTL_PARAMETERS MP, GL_CODE_COMBINATIONS GCC
                        WHERE MP.MATERIAL_ACCOUNT = GCC.CODE_COMBINATION_ID
                          AND GCC.SEGMENT1 = :P_LOB
                          AND (GCC.SEGMENT2 BETWEEN NVL (:P_DIV_FROM,
                                                         GCC.SEGMENT2)
                                                AND NVL (:P_DIV_TO, GCC.SEGMENT2)
                AND MTP.ORGANIZATION_CODE BETWEEN NVL (:P_FROM_ORG,
                                                       MTP.ORGANIZATION_CODE
                                              AND NVL (:P_TO_ORG,
                                                       MTP.ORGANIZATION_CODE
                AND MSI.CONCATENATED_SEGMENTS BETWEEN NVL
                                                        (:P_FROM_INV,
                                                         MSI.CONCATENATED_SEGMENTS
                                                  AND NVL
                                                        (:P_TO_INV,
                                                         MSI.CONCATENATED_SEGMENTS
           ORDER BY MSI.CONCATENATED_SEGMENTS, MTP.ORGANIZATION_CODE]]>
    </sqlStatement>
    <sqlStatement name="Q_2">
    <![CDATA[SELECT NVL (SUM (TRANSACTION_QUANTITY), 0) COMPLETION
           FROM MTL_MATERIAL_TRANSACTIONS
         WHERE INVENTORY_ITEM_ID = :INVENTORY_ITEM_ID
           AND ORGANIZATION_ID = :ORGANIZATION_ID
           AND TRANSACTION_TYPE_ID = 44
           AND TRUNC (TRANSACTION_DATE) = :TRX_DATE]]>
    </sqlStatement>
    <sqlStatement name="Q_3">
    <![CDATA[SELECT NVL (SUM (TRANSACTION_QUANTITY) * -1, 0) INCOMPLETION
          FROM MTL_MATERIAL_TRANSACTIONS
        WHERE INVENTORY_ITEM_ID = :INVENTORY_ITEM_ID
          AND ORGANIZATION_ID = :ORGANIZATION_ID
          AND TRANSACTION_TYPE_ID = 17
          AND TRUNC (TRANSACTION_DATE) = :TRX_DATE]]>
    </sqlStatement>
    <sqlStatement name="Q_4">
    <![CDATA[SELECT DESCRIPTION
          FROM FND_FLEX_VALUES_VL
        WHERE FLEX_VALUE_SET_ID = 1002470
              AND FLEX_VALUE = :P_LOB]]>
    </sqlStatement>
    <sqlStatement name="Q_5">
    <![CDATA[SELECT DESCRIPTION
         FROM FND_FLEX_VALUES_VL
        WHERE FLEX_VALUE_SET_ID = 1012471
          AND FLEX_VALUE = :P_DIV_FROM
          AND PARENT_FLEX_VALUE_LOW = :P_LOB]]>
    </sqlStatement>
    <sqlStatement name="Q_6">
    <![CDATA[SELECT DESCRIPTION
         FROM FND_FLEX_VALUES_VL
        WHERE FLEX_VALUE_SET_ID = 1012471
          AND FLEX_VALUE = :P_DIV_TO
          AND PARENT_FLEX_VALUE_LOW = :P_LOB]]>
    </sqlStatement>
    </dataQuery>
    <dataTrigger name="beforeReport" source="PRODUCTION.beforereporttrigger(:P_TRX_DATE_FROM,:P_TRX_DATE_TO)"/>
    <dataStructure>
    <group name="G_CONCATENATED_SEGMENTS" source="Q_1">
    <element name="CONCATENATED_SEGMENTS" datatype="charecter" value="CONCATENATED_SEGMENTS"/>
    <element name="DESCRIPTION" datatype="charecter" value="DESCRIPTION"/>
    <element name="TRANSACTION_UOM" datatype="charecter" value="TRANSACTION_UOM"/>
    <element name="INVENTORY_ITEM_ID" datatype="number" value="INVENTORY_ITEM_ID"/>
    <element name="ORGNIZATION_ID" datatype="number" value="ORGANIZATION_ID"/>
    <group name="G_TRX_DATE" source="Q_1">
    <element name="TRX_DATE" datatype="date" value="TRX_DATE"/>
    <group name="G_1" source="Q_1">
    <element name="ORGANIZATION_CODE" datatype="charecter" value="ORGANIZATION_CODE"/>
    <group name="G_ORGANIZATION_CODEC" source="Q_2">
    <element name="COMPLETION" datatype="number" value="COMPLETION"/>
    </group>
    <group name="G_ORGANIZATION_CODEI" source="Q_3">
    <element name="INCOMPLETION" datatype="number" value="INCOMPLETION"/>
    </group>
    </group>
    </group>
    </group>
    <group name="G_LOB" source="Q_4">
    <element name="CF_LOB" datatype="charecter" value="description"/>
    </group>
    <group name="G_FROM_DIV" source="Q_5">
    <element name="CF_DIVFROM" datatype="charecter" value="description"/>
    </group>
    <group name="G_TO_DIV" source="Q_6">
    <element name="CF_DIVTO" datatype="charecter" value="descrption"/>
    </group>
    <element name="CS_COUNT" function="count()" datatype="number" value="G_CONCATENATED_SEGMENTS.CONCATENATED_SEGMENTS"/>
    </dataStructure>
    </dataTemplate>
    Pls. suggest me.
    null

    Hi,
    without checked the whole document .... you've defined all paramaters as datataype charecter instead of character.
    Regards
    Rainer

  • BDOC Error : "BDoc stored before update task (intermediate state)"

    Hi Experts,
    I have stuck BDOCs under BDOC type "BUS_TRANS_MSG" and the error msg as "BDoc stored before update task (intermediate state)". The error occurs when BDoc Message was not written to qRFC queue. I checked the update tasks in transaction
    SM13 and could find the entries there. I opened one of the entry and was able to spot the error in one of the function module.
    The error was encountered at some later point in time and is been fixed. I now want to re-send the update so that the new update is written and the BDOCs are processed.
    Kindly guide me through the steps that need to be performed in order to re-process the BDOCS.
    Thanks,
    Chaudh

    Hi,
    BDocs were stuck at time when we really had a problem; now the problem is re-solved. I have checked SM13 we have entries highlighting the problem, but i really don't know how to re-update the error entries in SM13.
    I believe once that is done then i might possibly be able to re-process the BDOCs in SMW01.
    Thanks,
    Chaudh

  • Before update and after Update trigger

    Hi,
    I am following the below approach to overcome ORA-04091: table XXXX is mutating error.
    1. In the after update row level trigger i am capturing rowids of changed rows into a table type (of type rowid) defined in a package.
    2. In the after update statement level trigger i am using the data from the table type ( that got populated in the first step) to do my work.
    3. In the before update statement level trigger i am resetting the table type defined in the package.
    Now, can the below situation occur causing the system to fail
    1. A Update to the table occurred causing the before update statement level trigger to fire and reset the table type.
    2. After that row level after update trigger gets executed and captures the required data.
    3. Now before the after update statement level trigger gets executed a new update to the table happened ( to some other row as multiple users are using the application) causing the
    before update statement level to fire and erase the data from the table type?
    I want to know if above situation can occur or is the execution or before and after update triggers atomic?
    Thanks for helping.
    TIA
    Harsha

    A collection in a package is local to the session. And a given session can be processing one SQL statement at a time. So any concurrent updates would be happening in a different session with a different logical collection.
    You may encounter problems if your session is trying to update the same rows that other sessions are trying to update (whether via the original update statement or via the updates issued by the trigger). You could encounter performance problems because of row level locks or you could encounter deadlocks. But your session's collection won't be initialized by some other session's actions (other than DDL that replaced the package itself).
    Justin

  • After Update Trigger executes twice when single row is uptd thro proc

    We have the below trigger in our db. When a single record is updated using a procedure the trigger is executed twice and it inserts two records in other table.
    But when i issue an update statement using any sql client tool it is executing only once and inserts only one record in other table.
    Can any one please help me to find the reason?
    Trigger:*
    create or replace TRIGGER CX_HEADER_ESCL_T1 AFTER UPDATE OF STATUS ON CX_HEADER
    FOR EACH ROW
    DECLARE
    "b1-CTRIYJ" boolean := FALSE;
    BEGIN
    IF UPDATING('STATUS') AND(:NEW.status = 'SUCCESS') THEN
    "b1-CTRIYJ" := TRUE;
    END IF;
    IF "b1-CTRIYJ" = TRUE THEN
    INSERT
    INTO siebel.s_escl_req(req_id, created, bt_row_id, rule_id, tbl_name, created_by, group_id)
    VALUES('11111111', CURRENT_DATE, :NEW.row_id, '1-CTRIYJ', 'CX_HEADER', :NEW.last_upd_by, '1-2CU3');
    "b1-CTRIYJ" := FALSE;
    END IF;
    END;
    Procedure:
    CREATE OR REPLACE
    PROCEDURE CLOSE_BATCH
    (ChildRecordCount IN NUMBER, HeaderId IN VARCHAR2, CompletionStatus OUT VARCHAR2) AS
    CafeChildCount NUMBER;
    BEGIN
    select count(*) into CafeChildCount from SIEBEL.CX_CHILD where HEADER_ID=HeaderId;
    IF ChildRecordCount = CafeChildCount THEN
    update SIEBEL.CX_HEADER set STATUS ='SUCCESS', MODIFICATION_NUM = MODIFICATION_NUM+1 where HEADER_ID=HeaderId;
    CompletionStatus := 'SUCCESS';
    ELSE
    update SIEBEL.CX_CHILD set STATUS='FAILED' where HEADER_ID=HeaderId;
    update SIEBEL.CX_HEADER set STATUS='FAILED' where HEADER_ID=HeaderId;
    CompletionStatus := 'FAILED';
    END IF;
    commit;
    /*CompletionStatus := 'SUCCESS';*/
    EXCEPTION
    WHEN OTHERS THEN
    CompletionStatus := SQLCODE;
    rollback;
    END;

    Your problem seems not be related to the trigger restart issue I have already mentioned because you are using a AFTER UPDATE trigger and not a BEFORE UPDATE trigger:
    >
    BEFORE Triggers Fired Multiple Times
    If an UPDATE or DELETE statement detects a conflict with a concurrent UPDATE, then Oracle Database performs a transparent ROLLBACK to SAVEPOINT and restarts the update. This can occur many times before the statement completes successfully. Each time the statement is restarted, the BEFORE statement trigger is fired again. The rollback to savepoint does not undo changes to any package variables referenced in the trigger. Your package should include a counter variable to detect this situation.
    >
    If you are sure that you update a single row and that your trigger fires twice and if you can easiily reproduce the issue, I recommend that you contact Oracle Support and create a Service Request for your issue that could be an Oracle bug.

  • BDOC Stored before update task error

    Hi Experts,
    I am using FM CRMXIF_PRODUCT_MATERIAL_SAVE to update one of the custom aatributes in COMMPR01.
    once i run this FM i see an entry of bdoc in SMw01 with the below error
    "BDOC stored before update task(intermediate state).
    I checked ST22 and i saw no dumps, i checked Sm13 and i didnt see any update tasks. Cananyone help me?
    Thanks!

    HI Divya,
    BDoc Message was not written to qRFC queue, yet. Search for update tasks in transaction
    SM13. The sender creates a BDoc message to post data to the receivers. The application
    calls the messaging flow.
    Detection:
    Check if there are any update terminations which occurred in the update task
    by using transaction SM13. Check if there are inbound messages related to
    that outbound message, double-click u2018Original BDocu2019 field to display the
    original inbound message. Typically the inbound message (s-BDoc in flow
    context SI1 or m-BDoc in flow context MI0) is already on a final state F02, i.e.
    the validation was successful but the asynchronous update failed. The
    original inbound message in final state might have been already reorganized.
    Solution:
    Solve the problem with the open update tasks and then execute them again
    in SM13. Check whether after succesful reexecution in SM13 the BDoc state
    has been changed.
    If not, or if you donu2019t find any open updates, but you do find a corresponding
    original message, proceed as following:
    · Variant 1: Try to reprocess the inbound message to check if the newly
    created outbound message has also status I04. If BDoc is processed, no
    retry of the failed BDoc is allowed. Set the message as deleted.
    Reprocessing the related inbound message is sometimes not possible,
    because the state is final. In this case copy the inbound message using
    transaction SMW19 and set the new state of the copied message to I01.
    Then you can reprocess it.
    · Variant 2: Use the solution from SAP notes 876855 (CRM 3.X) or 835761
    (CRM 4.0) to convert the inbound s-BDoc into an error state E09.
    Advantage is, that in this state the inbound message does not get
    reorganized. More important, it also allows you to restart the inbound
    processing after the error situation has been resolved. However, in that
    case you need to delete the already pending update tasks from the
    previous run in transaction SM13.
    When there are no open update tasks anymore, check whether the data
    changes according to the inbound BDoc message have actually been posted
    to the CRM online application tables. If the changes are present (i.e. a new
    application object was succesfully created), you should not use variant 2,
    because you might get a problem of posting the same data again (i.e. getting
    an "insert duplicate record" situation).
    For more info about error analysis. please refer to
    http://saptricks.com/wp-content/uploads/2010/05/BestPractice-BDoc-Analysis-V2.pdf
    Cheers, Satish

Maybe you are looking for