I have 2 triggers and two tables.
One(trigger) is to insert inside one column in the other table when a row in first table is inserted, the other one prevent insert and update in that column.
I want to know if there is a way i can disable the second trigger that prevents the insert/update during the execution of first trigger.
This is how I understood the question. See if it helps.
Sample tables:
SQL> create table test (id number);
Table created.
SQL> create table test_2 (id number);
Table created.
A trigger on test_2 which prevents inserts:
SQL> create or replace trigger trg2
2 before insert or update on test_2
3 for each row
4 begin
5 raise_application_error(-20000, 'Not allowed');
6 end;
7 /
Trigger created.
Does it work?
SQL> insert into test_2 (id) values (1);
insert into test_2 (id) values (1)
*
ERROR at line 1:
ORA-20000: Not allowed
ORA-06512: at "SCOTT.TRG2", line 2
ORA-04088: error during execution of trigger 'SCOTT.TRG2'
Yes, it works.
Now, a trigger on test which is supposed to a) disable trg2 trigger and b) insert value into test_2. A straightforward code would then be
SQL> create or replace trigger trg1
2 before insert on test
3 for each row
4 begin
5 execute immediate 'alter trigger trg2 disable';
6 insert into test_2 (id) values (:new.id);
7 end;
8 /
Trigger created.
Let's test it:
SQL> insert into test (id) values (1);
insert into test (id) values (1)
*
ERROR at line 1:
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "SCOTT.TRG1", line 2
ORA-04088: error during execution of trigger 'SCOTT.TRG1'
Aha. Can't COMMIT in a trigger. Where is it? In dynamic SQL's alter trigger - it is a DDL and it implicitly commits. How to "fix" it? Make it (a trigger) an autonomous transaction:
SQL> create or replace trigger trg1
2 before insert on test
3 for each row
4 declare
5 pragma autonomous_transaction;
6 begin
7 execute immediate 'alter trigger trg2 disable';
8 insert into test_2 (id) values (:new.id);
9 end;
10 /
Trigger created.
SQL> insert into test (id) values (1);
insert into test (id) values (1)
*
ERROR at line 1:
ORA-06519: active autonomous transaction detected and rolled back
ORA-06512: at "SCOTT.TRG1", line 6
ORA-04088: error during execution of trigger 'SCOTT.TRG1'
That's another error; it says that - if we have an autonomous transaction - we have to either commit or roll back. Let's commit (because that's probably what you'd want to do):
SQL> create or replace trigger trg1
2 before insert on test
3 for each row
4 declare
5 pragma autonomous_transaction;
6 begin
7 execute immediate 'alter trigger trg2 disable';
8 insert into test_2 (id) values (:new.id);
9 commit;
10 end;
11 /
Trigger created.
SQL> insert into test (id) values (100);
1 row created.
SQL> select * From test;
ID
----------
100
SQL> select * from test_2;
ID
----------
100
SQL>
Right; now it works.
I suggest you re-read comments posted below your question, see this example and choose what to do.
Related
We have a requirement to disable a trigger only for a specific procedure run in ORACLE.
We have Table A and Table B.
The trigger is designed to insert into Table B for each insert or update of Table A.
The procedure makes entries to Table A.
How to enable/disable trigger in procedure?
The above link explains how to enable and disable the trigger during the procedure.
But my requirement is during this procedure run, if there are other inserts to Table A, then the trigger should run as expected.
Is this possible? Please help on how to achieve the same if possible.
You can use the DBMS_APPLICATION_INFO and SYS_CONTEXT to set any parameter in your procedure and then check for that parameter in the TRIGGER to see if you should take any action in the trigger or not as follows:
Table description:
SQL> DESC AA;
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 NOT NULL NUMBER
SQL>
Trigger code:
SQL> CREATE OR REPLACE TRIGGER AA_TRG BEFORE
2 INSERT OR UPDATE ON AA
3 FOR EACH ROW
4 BEGIN
5 IF SYS_CONTEXT(
6 'USERENV',
7 'ACTION'
8 ) = 'DISABLE_TRIGGER' THEN
9 DBMS_OUTPUT.PUT_LINE('TRIGGER DISABLED');
10 ELSE
11 DBMS_OUTPUT.PUT_LINE('TRIGGER ENABLED');
12 END IF;
13
14 DBMS_APPLICATION_INFO.SET_ACTION(ACTION_NAME => NULL);
15 END;
16 /
Trigger created.
SQL>
Disabled trigger procedure code:
SQL> CREATE OR REPLACE PROCEDURE AA_DISABLED_TRIGGER_PROC AS
2 BEGIN
3 DBMS_APPLICATION_INFO.SET_ACTION(ACTION_NAME => 'DISABLE_TRIGGER');
4 INSERT INTO AA VALUES ( 3 );
5
6 ROLLBACK;
7 END;
8 /
Procedure created.
SQL>
Enabled trigger procedure code:
SQL> CREATE OR REPLACE PROCEDURE AA_ENABLED_TRIGGER_PROC AS
2 BEGIN
3 INSERT INTO AA VALUES ( 3 );
4
5 ROLLBACK;
6 END;
7 /
Procedure created.
SQL>
Calling the procedures:
SQL>
SQL> SET SERVEROUT ON
SQL> BEGIN
2 AA_ENABLED_TRIGGER_PROC;
3 END;
4 /
TRIGGER ENABLED
PL/SQL procedure successfully completed.
SQL>
SQL> SET SERVEROUT ON
SQL> BEGIN
2 AA_DISABLED_TRIGGER_PROC;
3 END;
4 /
TRIGGER DISABLED
PL/SQL procedure successfully completed.
SQL>
SQL> SET SERVEROUT ON
SQL> BEGIN
2 AA_ENABLED_TRIGGER_PROC;
3 END;
4 /
TRIGGER ENABLED
PL/SQL procedure successfully completed.
SQL>
Not possible. If trigger is disabled, then it is disabled and won't work.
But, if you alter the table and add a column which says who is inserting rows into it, then you could use trigger's WHEN clause to distinguish this procedure from other inserters and either fire the trigger or not. It means, of course, that trigger remains enabled all the time.
How to add an extra column (say column_2) in the below INTO section of my code along with my Column_1. I assume we can do that by adding comma (,) and just add column_2 (like this INTO :new.Column_1, new.column_2). I'm missing something?
create or replace trigger trigger_name
BEFORE INSERT
ON table_name
FOR EACH ROW
BEGIN
SELECT SEQUENCE_NUMBER.NEXTVAL
INTO :new.Column_1
FROM dual;
END;
It is easy to confirm whether you are right (or wrong). I hope you got the answer during the past 6 hours. If not, here's an example:
SQL> create table test
2 (id number,
3 datum date);
Table created.
SQL> create sequence seq_test;
Sequence created.
SQL> create or replace trigger trg_bi_test
2 before insert on test
3 for each row
4 begin
5 select seq_test.nextval, sysdate
6 into :new.id, :new.datum
7 from dual;
8 end;
9 /
Trigger created.
SQL> insert into test (id) values (-1);
1 row created.
SQL> select * From test;
ID DATUM
---------- -------------------
1 21.06.2019 21:54:08
SQL>
I have multiple rows to insert in a table.
There are some constraints in the table which fails for few of the rows.
But with INSERT ALL statement, when it finds the first insert with constraint fails, it stops inserting to oracle db and rest of the data which are proper is also not inserted.
Will it be working this way only. Or do we have any method in which insert all valid data and ignore the other inserts in the INSERT ALL.
when it finds the first insert with constraint fails, it stops inserting to oracle db and rest of the data which are proper is also not inserted. Will it be working this way only.
Yes, it is designed to work that way. INSERT ALL statement will fail to insert if any one row errors out.
For example,
SQL> CREATE TABLE t(a NUMBER);
Table created.
SQL> ALTER TABLE t ADD CONSTRAINT t_unique UNIQUE(a);
Table altered.
SQL> INSERT INTO t(a) VALUES(1);
1 row created.
SQL> INSERT ALL
2 INTO t (a) VALUES (1)
3 INTO t (a) VALUES (2)
4 INTO t (a) VALUES (3)
5 SELECT * FROM dual;
INSERT ALL
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.T_UNIQUE) violated
SQL> SELECT * FROM t;
A
----------
1
If you want other values to be inserted which are correct, then put them as individual insert statements and execute all the insert statements as a script.
For example,
SQL> CREATE TABLE t(a NUMBER);
Table created.
SQL> ALTER TABLE t ADD CONSTRAINT t_unique UNIQUE(a);
Table altered.
SQL> INSERT INTO t(A) VALUES(1);
1 row created.
SQL> INSERT INTO t(a) VALUES(1);
INSERT INTO t(a) VALUES(1)
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.T_UNIQUE) violated
SQL> INSERT INTO t(A) VALUES(2);
1 row created.
SQL> INSERT INTO t(A) VALUES(3);
1 row created.
SQL> SELECT * FROM t;
A
----------
1
2
3
Is it possible to check the count of a table before any changes happen and the count after the insert and match them inside the same trigger?
for ex: old.count and new.count (before and after insert) ?
old.count and new.count (before and after insert)
Nothing stops you from using SELECT COUNT(*) in a before insert trigger. Of course, you won't do it in a after insert trigger, since a select count(*) on the same table on which an after trigger is defined would throw mutating table error. One way is autonomous transaction. But, in your case, it isn't that complex.
You could define a BEFORE INSERT TRIGGER and take the table count. The after insert count could be taken manually after the actual insert is done.
For example, I have a table t1 with one row. I have defined a before insert trigger on it, which would give me the table count before the insert happens.
SQL> DROP TABLE t1 PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE t1 (A NUMBER);
Table created.
SQL>
SQL> INSERT INTO t1 VALUES (1);
1 row created.
SQL>
SQL> SELECT * FROM t1;
A
----------
1
SQL>
SQL> CREATE OR REPLACE TRIGGER trg
2 BEFORE INSERT
3 ON t1
4 FOR EACH ROW
5
6 DECLARE
7 val number;
8 BEGIN
9 SELECT COUNT(*)
10 INTO val
11 FROM t1;
12
13 DBMS_OUTPUT.PUT_LINE('TABLE COUNT BEFORE INSERT = '||val);
14
15 END;
16 /
Trigger created.
SQL>
SQL> set serveroutput on
SQL> INSERT INTO t1 VALUES (1);
TABLE COUNT BEFORE INSERT = 1
1 row created.
SQL>
SQL> SELECT COUNT(*) FROM t1;
COUNT(*)
----------
2
SQL>
So, you see TABLE COUNT BEFORE INSERT = 1 and then after insert the count is 2.
I need to create a trigger that writes changes in a shadow table. I know how to create the trigger but my challenge is that I need the records in the new table to exist even after a rollback.
This is an example of how the output will look like
INSERT INTO department VALUES (95, 'PURCHASING', 'CHICAGO');<br>
ROLLBACK;
1 rows inserted.
rollback complete.
SELECT * FROM department_log;
DEPARTMENT_ID DEPARTMENT_NAME ADDRESS OPERATION_TIME
---------------------- -------------------- -------------------- ------------------
90 HR CHICAGO 03-NOV-11
95 PURCHASING CHICAGO 03-NOV-11
SELECT * from department WHERE department_id >= 90;
DEPARTMENT_ID DEPARTMENT_NAME ADDRESS
---------------------- -------------------- --------------------
90 HR CHICAGO
You'll need to use autonomous transactions.
SQL> create table t (col1 number);
Table created.
SQL> create table t_shadow( col1 number, dt date );
Table created.
SQL> create trigger trg_t
2 before insert on t
3 for each row
4 declare
5 pragma autonomous_transaction;
6 begin
7 insert into t_shadow( col1, dt )
8 values( :new.col1, sysdate );
9 commit;
10 end;
11 /
Trigger created.
SQL> insert into t values( 1 );
1 row created.
SQL> rollback;
Rollback complete.
SQL> select * from t;
no rows selected
SQL> select * from t_shadow;
COL1 DT
---------- ---------
1 09-NOV-11
Note that if you find yourself using autonomous transactions for anything other than persistent logging, you are almost certainly doing something wrong. Autonomous transactions are a very dangerous and very frequently misused feature.
You would need to declare the trigger as an Autonomous Transaction
PRAGMA AUTONOMOUS_TRANSACTION;
This decouples the trigger code from the main transaction, so even if the main insertion into the table (which fired the trigger) rollsback, the trigger is executed in a different transactional context and can commit / rollback independently.