Statement trigger

When do we use statement triggers? i need one practical example... like row level triggers help in audit or journalling. Plz reply asap.

vidya.ramachandra wrote:
The document did not help much ... as i could not get a satisfying answer out of it.Well if this is not useful enough
For example, if a statement deletes 100 rows from a table, a statement-level DELETE trigger is fired only once. Statement triggers are useful if the code in the trigger action does not depend on the data provided by the triggering statement or the rows affected.You can always enter statement trigger in the manual search box.
Refine results by Related examples
http://www.oracle.com/pls/db112/ranked?word=statement+trigger&example=1
And choose something more useful to you.

Similar Messages

  • How to get triggering sql text in a statement trigger

    hi,
    I need to get sql text that run on the table in statement trigger on that table. I will log sql statements that run on table for a few weeks. I search for it, there is a ORA_SQL_TEXT function but this function is working on event triggers not statement or for each row triggers.
    is there any other way to achive that ?

    You can use AUDIT
    http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_4007.htm#i2115972
    >
    Auditing Queries on a Table: Example To choose auditing for every SQL statement that queries the employees table in the schema hr, issue the following statement:
    AUDIT SELECT
    ON hr.employees;
    To choose auditing for every statement that successfully queries the employees table in the schema hr, issue the following statement:
    AUDIT SELECT
    ON hr.employees
    WHENEVER SUCCESSFUL;
    To choose auditing for every statement that queries the employees table in the schema hr and results in an Oracle Database error, issue the following statement:
    AUDIT SELECT
    ON hr.employees
    WHENEVER NOT SUCCESSFUL;
    Auditing Inserts and Updates on a Table: Example To choose auditing for every statement that inserts or updates a row in the customers table in the schema oe, issue the following statement:
    AUDIT INSERT, UPDATE
    ON oe.customers;

  • Diff. of trigger for row and statement ?

    whats the difference between
    trigger for row
    and
    trigger for statement

    The FOR EACH ROW option determines whether the trigger is a row trigger or a statement trigger. If you specify FOR EACH ROW, then the trigger fires once for each row of the table that is affected by the triggering statement. The absence of the FOR EACH ROW option indicates that the trigger fires only once for each applicable statement, but not separately for each row affected by the statement.

  • Global temp table trigger error on Oracle AS

    we have a set of triggers that load a temp table in the before delete,update and process the table in an after statement trigger. the data that's loaded is a complaintid and when the complaintid is selected into a variable in the after statement, a No data found error is fired. This only happens on Oracle AS both 9i and 10g, it does not happen on jboss. All the app servers use connection pooling and they are 9i Enterprise Edition Dedicated database servers.
    Is it possible that there is a bug in Oracle AS that allows multiple sessions to affect the same global variables ?
    Sorry it's a long one, but I wanted to include everything I could
    table creation script.
    CREATE GLOBAL TEMPORARY TABLE TEMPEVENTS
    (     COMPLAINTID VARCHAR2(20) NOT NULL ENABLE,
         COMPLAINTEVENTID NUMBER NOT NULL ENABLE,
         STARTDATE DATE,
         EVENTTYPE NUMBER,
         EVENTSUBTYPE NUMBER,
         DELETED NUMBER
    ) ON COMMIT DELETE ROWS
    Before update trigger-- as a test I saved the data in a permanent table and all columns have usable values.
    create or replace trigger BeforeUpdateReportDataROW
    BEFORE Delete or Update of deleted, startdate on complaintevents
    FOR EACH ROW
    BEGIN
    IF (DELETING AND :old.deleted = 0) OR (UPDATING AND :new.deleted=1 AND :old.startDate = :new.startDate) THEN
         TEMPDATA.v_triggerType := 'D';
    ELSIF UPDATING AND :old.deleted=1 AND :old.startDate = :new.startDate THEN /*undeleting*/
         TEMPDATA.v_triggerType := 'U';
    ELSIF UPDATING AND :old.startDate != :new.startDate THEN /*new date*/
         TEMPDATA.v_triggerType := 'S';
    ELSE
         TEMPDATA.v_triggerType := 'N';
    END IF;
    TEMPDATA.v_NumEntries := TEMPDATA.v_NumEntries + 1;
    TEMPDATA.v_complaintids(TEMPDATA.v_NumEntries) := :old.complaintid;
    TEMPDATA.v_complainteventids(TEMPDATA.v_NumEntries) := :old.complainteventid;
    END;
    After statement trigger -- the error happens on the
    SELECT complaintid
    INTO complaintid
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index)
    AND complainteventid = tempdata.v_complainteventids (loop_index);
    statement. this is all one transaction the complaintid is loaded from the complaintevent table, and is not a primary key, nor is there only one record in the complaintevent table for each complaintid.
    create or replace trigger complaintevents_del_upd_trig
    AFTER DELETE OR UPDATE OF deleted, startdate
    ON complaintevents
    DECLARE
    complaintid VARCHAR2 (20);
    loop_index NUMBER;
    hold_complaintid VARCHAR2 (20);
    BEGIN
    IF tempdata.v_triggertype = 'D'
    THEN /*deleting event*/
    hold_complaintid := ' ';
    FOR loop_index IN 1 .. tempdata.v_numentries
    LOOP
    SELECT complaintid
    INTO complaintid
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index)
    AND complainteventid = tempdata.v_complainteventids (loop_index);
    IF hold_complaintid != complaintid
    THEN
    INSERT INTO tempevents
    (complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted)
    SELECT complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index);
    END IF;
    DELETE tempevents
    WHERE complainteventid =
    tempdata.v_complainteventids (loop_index)
    OR deleted = 1;
    hold_complaintid := complaintid;
    END LOOP;
    ELSIF tempdata.v_triggertype = 'U'
    THEN /*undeleting*/
    hold_complaintid := ' ';
    FOR loop_index IN 1 .. tempdata.v_numentries
    LOOP
    SELECT complaintid
    INTO complaintid
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index)
    AND complainteventid = tempdata.v_complainteventids (loop_index);
    IF hold_complaintid != complaintid
    THEN
    INSERT INTO tempevents
    (complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted)
    SELECT complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index);
    END IF;
    DELETE tempevents
    WHERE deleted = 1;
    INSERT INTO tempevents
    (complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted)
    SELECT complaintid, complainteventid, startdate, eventtype,
    eventsubtype, 0
    FROM complaintevents
    WHERE complainteventid =
    tempdata.v_complainteventids (loop_index);
    hold_complaintid := complaintid;
    END LOOP;
    ELSIF tempdata.v_triggertype = 'S'
    THEN /*date change*/
    hold_complaintid := ' ';
    FOR loop_index IN 1 .. tempdata.v_numentries
    LOOP
    SELECT complaintid
    INTO complaintid
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index)
    AND complainteventid = tempdata.v_complainteventids (loop_index);
    IF hold_complaintid != complaintid
    THEN
    INSERT INTO tempevents
    (complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted)
    SELECT complaintid, complainteventid, startdate, eventtype,
    eventsubtype, deleted
    FROM complaintevents
    WHERE complaintid = tempdata.v_complaintids (loop_index);
    END IF;
    DELETE tempevents
    WHERE deleted = 1;
    hold_complaintid := complaintid;
    END LOOP;
    ELSE
    RETURN;
    END IF;
    END;

    CREATE GLOBAL TEMPORARY TABLE test_glb ON COMMIT DELETE ROWS
    AS SELECT * FROM test1;btw I'm assuming you are just using the SELECT statement to copy the definition of test1. Since DDL statements commit, there will be no rows in test_glb after creating it.
    Edited by: William Robertson on Feb 23, 2009 7:31 AM

  • Trigger in mutation - Update another rows in the same table with a trigger

    Hi ,
    I try to do a before update trigger on a table , but the trigger is in mutation. I understand why it do that but my question is :
    How can I update other rows in the same table when a UPDATE is made on my table??????
    Here is my trigger :
    CREATE OR REPLACE TRIGGER GDE_COMPS_BRU_5 BEFORE
    UPDATE OF DEPARTEMENT--, DISCIPLINE, DEG_DEMANDE, CE_ETAB
    ON GDEM.COMPOSITION_SUBV
    FOR EACH ROW
    Organisme : FQRNT-FQRSC
    Date de création : 14-07-2011
    Date de modification :
    Modifié par :
    Auteur : Johanne Plamondon
    Description : Ce déclencheur s'executera lors de la modification
    du responsable dans la table COMPOSITION_SUBV
    DECLARE
    V_OSUSER V$SESSION.OSUSER%TYPE;
    V_PROGRAM V$SESSION.PROGRAM%TYPE;
    V_TERMINAL V$SESSION.TERMINAL%TYPE;
    V_MACHINE V$SESSION.MACHINE%TYPE;
    V_MODULE V$SESSION.MODULE%TYPE;
    V_LOGON_TIME V$SESSION.LOGON_TIME%TYPE;
    V_AUDIT_ID NUMBER;
    vSEQ NUMBER;
    i NUMBER;
    vID DEMANDE.ID%TYPE;
    BEGIN
    begin
    SELECT OSUSER, PROGRAM, TERMINAL,MACHINE,MODULE, LOGON_TIME
    INTO V_OSUSER,V_PROGRAM,V_TERMINAL,V_MACHINE,
    V_MODULE,V_LOGON_TIME
    FROM V$SESSION
    WHERE TYPE = 'USER'
    AND USERNAME = USER
    AND LAST_CALL_ET IN (0,1)
    AND ROWNUM < 2;
    exception when others then null; end;
    IF NVL(:NEW.SC_PART,' ') = 'CHC' THEN
    SELECT COUNT(*)
    INTO i
    FROM DEMANDE
    WHERE DEM_REF = :NEW.DEM_ID
    AND PER_NIP = :NEW.PER_NIP;
    IF i = 1 THEN
    SELECT ID
    INTO vID
    FROM DEMANDE
    WHERE DEM_REF = :NEW.DEM_ID
    AND PER_NIP = :NEW.PER_NIP;
    UPDATE COMPOSITION_SUBV
    SET --CE_ETAB     = :NEW.CE_ETAB,
    --DISCIPLINE  = :NEW.DISCIPLINE,
    DEPARTEMENT = :NEW.DEPARTEMENT,
    --DEG_DEMANDE = :NEW.DEG_DEMANDE,
    DATE_MODIF = SYSDATE,
    USER_MODIF = V_OSUSER
    WHERE DEM_ID = vID
    AND PER_NIP = :NEW.PER_NIP
    AND ANNEE = :NEW.ANNEE;
    END IF;
    END IF;
    /*EXCEPTION
    WHEN OTHERS THEN
    NULL;*/
    END;

    A standard disclaimer, the mutating trigger error is telling you that you really, really, really don't want to be doing this. It generally indicates a major data model problem when you find yourself in a situation where the data in one row of a table depends on the data in another row of that same table. In the vast majority of cases, you're far better off fixing the data model than in working around the problem.
    If you are absolutely sure that you cannot fix the data model and must work around the problem, you'll need
    - A package with a collection (or global temporary table) to store the keys that are modified
    - A before statement trigger that initializes the collection
    - A row-level trigger that adds the keys that were updated to the collection
    - An after statement trigger that iterates over the data in the collection and updates whatever rows need to be updated.
    If you're on 11g, this can be simplified somewhat by using a compound trigger with separate before statement, row-level, and after statement sections.
    Obviously, though, this is a substantial increase in complexity over the single trigger you have here. That's one of the reasons that it's generally a bad idea to work around mutating table exceptions.
    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.

  • 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;

  • How do you audit a clob from a trigger

    I've manged to get the :OLD.clob_value to be audited but I cannot audit a :NEW.clob_value in an update or insert trigger. I even created a before insert for each row trigger and an after statement trigger then try to simply select the clob_value into the audit table and this does not work either.
    Has anyone ever had to audit a CLOB in a trigger?
    Thanks.

    According to Oracle's Support website "Metalink.com" see link below, You cannot access :new.clob in a trigger if your using Oracle 8i. They supposedly fixed this bug in oracle 9.0.2.
    http://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_id=1226565&p_database_id=BUG
    Has anyone found a work around for Oracle 8i?

  • Need help in Statement level triggers.

    Hi All,
    I would like to clarify few things about statement level triggers. here are my doubts,
    1. does a statement level trigger have access to the column values of each row that the trigger affects? if so provide me with some examples.
    Thanks,
    james.

    Not by default. If you need to see the column values in an after-statement trigger, you need to use a row-level trigger to accumulate the values in a package variable. This approach would use a before-statement trigger to clear the variable (a table of records based on the rowtype of the table, usually), the after-row trigger to add a row's column values, and then the after-statement trigger to loop through the PL/SQL table (array, collection, etc.) and do whatever is needed.

  • ORA-04091: table name is mutating, trigger/function may not see it

    Hi,
    I have a row level before update trigger written on a table A which calls a procedure to undergo some processing. Procedure has some select queries against table A and it inturn causes the following error.
    ORA-04091: table name is mutating, trigger/function may not see it
    To overcome this I have used a combination of PL/SQL collection types (nested tables based on the following definition TYPE t_table_a is table of A.colname%TYPE index by binary_integer;), a row level before update trigger and statement level after update trigger. The mutating problem is fixed, but to update one row of data it took around 3 min and I am wondering if its the problem with PL/SQL tables I have used.
    In before update trigger I am storing the unique id's which needs to be updated into the PL/SQL table and in the after update trigger I am looping through the PL/SQL table and peforming the rest of the processing by calling in the procedure.
    Can anyone help how to minimize the run time of this process or if any other better solution exists?
    Thanks for the help

    Triggers raise the mutating table issue, because else they could be used to create endless loops. If you work around the mutating table issue, then you should make sure not to create an endless loop yourself. This would be possible.
    You description also seems to imply something like this.
    Without code it is impossible to say something specific.
    - Do you initialize your collection in a before statement trigger?
    - Is your looping mechanism somehow broken?
    - Do you update the same table again and again and again?

  • How to start and stop video acquisitio​n in a state machine

    hello,
    I'm a neuroscience student and here's what I'm trying to do: 1) trigger a GigE camera (200fps), 2) start video acquisition, 3) trigger a light that will stay on for x miliseconds, 4) trigger a valve that will blow an air puff, 5) stop the tone and the valve simultaneously and 5) stop the video acquisition 1second after 4). For that, my VI is a state machine, with a state for each trigger (ex, 1 state for trigger camera, 1 state for trigger light, ect) plus a state to "stop" and a state "time to wait". Everything was working except the video acquisition - the program would trigger the camera but only acquire one frame, because it wasn't running in a while loop and this is my first question: for a video acquisition is it always necessary to have a while loop?
    I assumed the answer was yes, so I built a "consumer" loop for the camera. Putting a queue in the state "trigger camera" in the producer loop, I was then able to start the video acquisition but now the problem is to stop it in the right time. I have another queue in the "stop" state in the producer loop, but it isn't able to start the "stop" state in the consumer loop, I think that may be because the consumer loop gets "stuck" in the while loop.
    I hope you can help me, the VI is attached. Thanks!
    Solved!
    Go to Solution.
    Attachments:
    trigger_cam.jpg ‏345 KB
    trigger_stop.jpg ‏354 KB
    Conditioning MS vi 2010.zip ‏68 KB

    Hi Gak,
    Thanks for the suggestions. I still didn't got it to work though. I moved the stop command to inside the while loop like you said but it didn't work. The problem seems to be in the communication between the producer/consumer loops. When I run the VI in highlight, the queue message "trigger camera" leaves the producer and arrives at the consumer loop in the appropriate time, starting the "trigger camera" state of the case structure. However, the message "stop" doesn't seem to be sent by the producer loop, so the consumer doesn't receive a signal to start the "stop" state of the case structure. Can you think of anything I should change in the producer loop so that the second state (stop) is added to the queue?
    About the functional global, I read about it, it seems that either that or a local variable could work, but I don't quite know how to implement it in my state machine, since the stop of the first while loop isn't activated in the "stop" state but in the "shutdown" state. It works more or less like this: after 10 loops of triggering and stopping the camera, light and valve (so after acquiring 10 movies), it goes for shutdown. Can you show me what you had in mind with the functional variable?
    Attachments:
    Untitled.jpg ‏286 KB

  • How to call a package in a trigger

    I have package that is called via a "Submit" in a from used to enter daily production. We are implementing a barcoding system that will automatically populate the tables behind this form (one header and one line level table). I need to write a trigger or something that fires up the code behind the 'Submit' process whenever these tables are updated.
    Is there a way to do this by calling the package in a trigger?
    Please help.
    Thanks
    Edited by: asgar_amin on Feb 3, 2009 10:50 AM

    I'm not quite sure what your requirement is.
    Do you want to know which forms-trigger you can use to call your submit-package, or do you want to know how to call the submit-package from a database-trigger?
    If the second one, it depends on what parameters your package-procedur/function gets as IN-parameters. Is it the ID of the header-record, the detail-record or no parameter at all.
    Depending on that you could either use a AFTER-STATEMENT-trigger on either Header or lines-tables, or if you have to gather the ids a combination of a BEFORE-STATEMENT, an AFTER-INSERT FOR EACH ROW and an AFTER-STATEMENT-trigger.
    To go more into detail, please provide some more information.

  • How to reference LONG field in trigger

    I am trying to create a trigger (update and delete) for auditing purposes. The source table has a long field and I need to insert all columns (which includes the long field) into an audit table if any column in the source record changes or if the source record is deleted. I cannot reference :old.longfield or do a select into.
    If anyone has a suggestion or has done it in the past, please email me at [email protected] or post an answer.
    Thank You so much for your help !!!!!

    As you have noticed, you cannot reference the value of a LONG column using :old/:new in a trigger. The work around is to instead process your audit information (including the LONG value) in an after statement trigger. Here is an example to get you started:
    http://asktom.oracle.com/pls/ask/f?p=4950:8:605685::NO::F4950_P8_DISPLAYID

  • Dynamic references to trigger vars :new and :old

    Is there any way to dynamicly refer to the :old and :new bind
    variables available in triggers?
    I'm looking for a method to make a standard processing system
    that processes based on column-names. I want to avoid calling my
    handling system staticly for each field in the table.
    Ie. I want to refer to :old.data_column in a way where I can
    loop through all the fields of the table.
    Hints, tips and ideas would be greatly apprechiated.

    You can't have dynamic PL/SQL containing ":NEW" or ":OLD" in
    database triggers.
    But in some cases, if your table has primary key (PK)
    or unique key (UK), you can use AFTER STATEMENT triggers
    in following way
    (this is like well-known solution for mutating error problem):
    1. create database package with PL/SQL table
    (for storing PK values)
    2. clear PL/SQL table in BEFORE STATEMENT trigger
    3. populate PL/SQL table with PK value
    in BEFORE (or AFTER) ROW trigger
    4. read rows in AFTER STATEMENT trigger with dynamic PL/SQL,
    using PKs from PL/SQL table and using dynamically selected
    column names with statement
    SELECT column_name
    FROM user_tab_columns
    WHERE UPPER (table_name) = UPPER (p_table);"
    (you can read NEW values of columns and,
    with AUTONOMOUS_TRANSACTION, OLD values too)
    For example (scott.dept table):
    CREATE OR REPLACE TRIGGER bus_dept
    BEFORE UPDATE ON dept
    BEGIN
    plsql_table.clear;
    END;
    CREATE OR REPLACE TRIGGER bur_dept
    BEFORE UPDATE ON dept
    FOR EACH ROW
    BEGIN
    plsql_table.populate_with_id (:NEW.deptno);
    END;
    CREATE OR REPLACE TRIGGER aus_dept
    AFTER UPDATE ON dept
    DECLARE
    v_current_id dept.deptno%TYPE;
    BEGIN
    dynamic_new_old.set_table_name ('dept');
    dynamic_new_old.set_pk_name ('deptno');
    dynamic_new_old.create_column_names;
    WHILE plsql_table.id_exists LOOP
    v_current_id := plsql_table.current_id;
    DBMS_OUTPUT.PUT_LINE ('OLD VALUES:');
    dynamic_new_old.display_old_values (v_current_id);
    DBMS_OUTPUT.PUT_LINE ('NEW VALUES:');
    dynamic_new_old.display_new_values (v_current_id);
    DBMS_OUTPUT.PUT_LINE ('*****');
    END LOOP;
    END;
    CREATE OR REPLACE PACKAGE plsql_table IS
    PROCEDURE clear;
    PROCEDURE populate_with_id (p_id dept.deptno%TYPE);
    FUNCTION id_exists RETURN BOOLEAN;
    FUNCTION current_id RETURN dept.deptno%TYPE;
    END;
    CREATE OR REPLACE PACKAGE BODY plsql_table IS
    TYPE type_plsql_table IS TABLE OF dept.deptno%TYPE INDEX BY
    BINARY_INTEGER;
    m_plsql_table type_plsql_table;
    -- prefiks m_ is for module level variable (defined in package
    body)
    -- prefiks g_ is for global variable (defined in package
    specification)
    m_rec_number BINARY_INTEGER;
    PROCEDURE clear IS
    BEGIN
    m_rec_number := 0;
    END;
    PROCEDURE populate_with_id (p_id dept.deptno%TYPE) IS
    BEGIN
    m_rec_number := m_rec_number + 1;
    m_plsql_table (m_rec_number) := p_id;
    END;
    FUNCTION id_exists RETURN BOOLEAN IS
    BEGIN
    RETURN (m_rec_number > 0);
    END;
    FUNCTION current_id RETURN dept.deptno%TYPE IS
    v_id dept.deptno%TYPE;
    BEGIN
    v_id := m_plsql_table (m_rec_number);
    m_rec_number := m_rec_number - 1;
    RETURN v_id;
    END;
    END;
    CREATE OR REPLACE PACKAGE dynamic_new_old IS
    PROCEDURE set_table_name (p_table VARCHAR2);
    PROCEDURE set_pk_name (p_pk VARCHAR2);
    PROCEDURE create_column_names;
    PROCEDURE display_old_values (p_id dept.deptno%TYPE);
    PROCEDURE display_new_values (p_id dept.deptno%TYPE);
    END;
    CREATE OR REPLACE PACKAGE BODY dynamic_new_old IS
    m_table VARCHAR2 (30);
    m_pk VARCHAR2 (30);
    m_columns VARCHAR2 (1000);
    PROCEDURE set_table_name (p_table VARCHAR2) IS
    BEGIN
    m_table := p_table;
    END;
    PROCEDURE set_pk_name (p_pk VARCHAR2) IS
    BEGIN
    m_pk := p_pk;
    END;
    PROCEDURE create_column_names IS
    v_first_column BOOLEAN;
    BEGIN
    v_first_column := TRUE;
    FOR rec IN
    (SELECT column_name
    FROM user_tab_columns
    WHERE UPPER (table_name) = UPPER (m_table))
    LOOP
    IF v_first_column THEN
    v_first_column := FALSE;
    m_columns := 'v_record.' || rec.column_name;
    ELSE
    m_columns := m_columns ||
    '||' || '''--''' || '|| v_record.' || rec.column_name;
    END IF;
    END LOOP;
    END;
    PROCEDURE display_values (p_id dept.deptno%TYPE) IS
    v_cursor INTEGER;
    v_rows_processed INTEGER;
    v_statement VARCHAR2 (32000);
    BEGIN
    v_statement :=
    ' DECLARE ' ||
    ' v_record ' || m_table || '%ROWTYPE;' ||
    ' BEGIN' ||
    ' SELECT * INTO v_record' ||
    ' FROM ' || m_table ||
    ' WHERE ' || m_pk || ' = ' || p_id || ';' ||
    ' DBMS_OUTPUT.PUT_LINE (' || m_columns || ');' ||
    ' END;';
    v_cursor := DBMS_SQL.OPEN_CURSOR;
    DBMS_SQL.PARSE (v_cursor, v_statement, DBMS_SQL.V7);
    v_rows_processed := DBMS_SQL.EXECUTE (v_cursor);
    DBMS_SQL.CLOSE_CURSOR (v_cursor);
    EXCEPTION
    WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE (sqlerrm);
    IF DBMS_SQL.IS_OPEN (v_cursor) THEN
    DBMS_SQL.CLOSE_CURSOR (v_cursor);
    END IF;
    END;
    PROCEDURE display_old_values (p_id dept.deptno%TYPE) IS
    PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
    display_values (p_id);
    END;
    PROCEDURE display_new_values (p_id dept.deptno%TYPE) IS
    BEGIN
    display_values (p_id);
    END;
    END;
    Note that this code is not generic, because uses
    "dept.deptno%TYPE". If all your PKs has the same declaration
    (for example NUMBER), then you can write generic solution.
    If you need only OLD values, you can write a simpler solution
    (without statement triggers and "plsql_table" package),
    using "dynamic_new_old" package and AUTONOMOUS_TRANSACTION
    in BEFORE (or AFTER) ROW trigger.
    Regards
    Zlatko Sirotic

  • Trigger execution

    I have asked in an interview i have 4 triggers(statement,rowwith before and after trigger).
    Which triggers will execute in which Order?

    Depends. For example, deleting from parent table where child table FK has ON DELETE CASCADE. In such case child table BEFORE statement trigger is executed for first child table delete statement only and child AFTER statement trigger is executed for last child table delete statement only:
    CREATE TABLE PARENT(
                        ID NUMBER
    ALTER TABLE PARENT
      ADD CONSTRAINT PARENT_PK
        PRIMARY KEY(
                    ID
    CREATE TRIGGER PARENT_BD_TRG
      BEFORE DELETE
      ON PARENT
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Parent before DELETE statement.'
    END;
    CREATE TRIGGER PARENT_BDR_TRG
      BEFORE DELETE
      ON PARENT
      FOR EACH ROW
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Parent before DELETE row.'
    END;
    CREATE TRIGGER PARENT_AD_TRG
      AFTER DELETE
      ON PARENT
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Parent after DELETE statement.'
    END;
    CREATE TRIGGER PARENT_ADR_TRG
      AFTER DELETE
      ON PARENT
      FOR EACH ROW
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Parent after DELETE row.'
    END;
    INSERT
      INTO PARENT
      SELECT  LEVEL
        FROM  DUAL
        CONNECT BY LEVEL <= 2
    CREATE TABLE CHILD(
                        ID NUMBER
    ALTER TABLE CHILD
      ADD CONSTRAINT CHILD_PARENT_FK
        FOREIGN KEY(
                    ID
        REFERENCES PARENT(
                          ID
        ON DELETE CASCADE
    CREATE TRIGGER CHILD_BD_TRG
      BEFORE DELETE
      ON CHILD
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Child before DELETE statement.'
    END;
    CREATE TRIGGER CHILD_BDR_TRG
      BEFORE DELETE
      ON CHILD
      FOR EACH ROW
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Child before DELETE row.'
    END;
    CREATE TRIGGER CHILD_ADR_TRG
      AFTER DELETE
      ON CHILD
      FOR EACH ROW
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Child after DELETE row.'
    END;
    CREATE TRIGGER CHILD_AD_TRG
      AFTER DELETE
      ON CHILD
      BEGIN
          DBMS_OUTPUT.PUT_LINE(
                               'Child after DELETE statement.'
    END;
    INSERT
      INTO CHILD
      SELECT  CEIL(LEVEL / 2)
        FROM  DUAL
        CONNECT BY LEVEL <= 4
    COMMIT
    SET SERVEROUTPUT ON
    DELETE PARENT
    Parent before DELETE statement.
    Child before DELETE statement.
    Parent before DELETE row.
    Child before DELETE row.
    Child after DELETE row.
    Child before DELETE row.
    Child after DELETE row.
    Parent after DELETE row.
    Parent before DELETE row.
    Child before DELETE row.
    Child after DELETE row.
    Child before DELETE row.
    Child after DELETE row.
    Parent after DELETE row.
    Child after DELETE statement.
    Parent after DELETE statement.
    2 rows deleted.
    SQL>
    SY.

Maybe you are looking for

  • Ipod shuffle not showing in my computer

    I have the same problem everyone else and none of the antidotes or fixes seem to work for me. My ipod shows up in the device manager as an ipod but shows as other device. Also the ipod doesnt show in my computer at all. I keep getting a cant "find dr

  • Elements 6, Canon 50D Raw Files, Windows Vista

    Hi all...my first post here... I'm able to load and see my Raw files in the organizer after loading the latest ACR. But when I browse through the files, after a bit,  I get an error message that Elements needs to close. After closing I check my task

  • Best practice for this project?

    Hello, Total n00b here, so please bare with me! I'm working on one of my first AE projects getting my feet wet as well as following along with some books and Lynda.com training vids, but I thought I'd post here as well. The project I'm working on is

  • Weird : I redeemed $30 code, verified as unlocked by 3 reps, and then last rep said im not

    Fellas, Ive heard some werid crap happeniing with their gamers club unlocked $30/2 year renewal promotion. heres my story: after 4 hours, i finally got it redeemed. i verified i was unlocked with 3 different reps because each time i tried to make an

  • Help migrating with Time Machine

    Hi there! I have a couple of questions regarding Time Machine,thanks in advance to anyone can help. I have to sell my Imac and i have to wait for a couple of weeks until i get a new one. What i need to know is if it is possible mirror my Imac,System,