Reverse a commit value in oracle sql - oracle

I've wrote a procedure as follows
Create or replace procedure raise_salary(
v_id IN emp.empno%TYPE) AS
Begin
update emp
set sal = sal*1.10
where empno=v_id;
commit;
End;
I realized that i didn't create an exception to rollback the value.
I want to go back to its original value. the value cannot be decreased as i get the following error.
ORA-20187: Salaries cannot be decreased
how do I go back to the original value. I've dropped the procedure but now since i already executed it, it increased it already. Seems like its a fixed value now. What do I do?

Dropping the procedure has absolutely nothing to do with reversing the effects of running it.
It sounds like there is a trigger on the table preventing you from doing the update that you want to do. One option is to disable the trigger. The error stack from the update should tell you its name. You would execute ALTER TRIGGER <triggername> DISABLE, then run your update, then `ALTER TRIGGER ENABLE'.
Another possible workaround could be to insert the row into a second table, update it there, then delete and re-insert it in the original table. This could also run afoul of triggers if someone has tried to prevent inserts or deletes on the table.
This is all assuming you are in an environment where bypassing logic control implemented by someone else is appropriate. Presumably the trigger exists for a reason.

select trigger_name from user_triggers where table_name='EMP'
Will show you trigger names of table you want to rollback. Then disable them like previous answer show. Dont foget to enable them back.
Begin
For cur in (select trigger_name from user_triggers where tbale_name='EMP') loop
Execute immediate 'alter trigger'||cur.trigger_name||' disable';
Update emp set ....your update DML;
Execute immediate 'alter trigger'||cur.trigger_name||' enable';
end loop;
End;
I hope, it help you.

Related

Alter trigger from another trigger

I wish to have alter trigger under another trigger.
CREATE TRIGGER izmeni_naziv_kupac
AFTER UPDATE OF naziv ON Kupac
FOR EACH ROW
DECLARE
novi_naziv varchar2(255);
pibK INT;
BEGIN
EXECUTE IMMEDIATE 'ALTER TRIGGER ZabranaPromeneNazivaKupaca DISABLE';
pibK := :new.pib;
novi_naziv := :new.naziv;
UPDATE Porudzbina
SET naziv_kupca = novi_naziv
WHERE kupac_PIB = pibK;
EXECUTE IMMEDIATE 'ALTER TRIGGER ZabranaPromeneNazivaKupaca ENABLE';
END;
Problem is that system sent error message:
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "SYSTEM.IZMENI_NAZIV_KUPAC", line 5
ORA-04088: error during execution of trigger 'SYSTEM.IZMENI_NAZIV_KUPAC'
This is not a practical way to manage trigger activation, and for the same reason, I'd advise against using 'autonmous' to work around it because its very rare to want to turn off a trigger for all users, because typically that breaks an application.
More likely is that you want to disable a trigger for this current session, for example, to perform some sort of maintenance activity etc. For this task, you would code the trigger to have a flag in order to let you control its execution.
Thus your code would be along the lines of (psuedo-code):
trigger my_trigger
before insert ...
begin
if i_am_meant_to_fire then
...
... my normal code
...
end if;
end;
where you then have session level control over when the trigger should take any action. It is always enabled, but might not do anything based on the flag.
A full walkthrough of some options here
https://youtu.be/P1OFbNhgT1k

How to create a trigger that wont hold the entire transaction till it complete?

There is a procedure which have insert operation in middle for a table. The table contain a trigger and because of that the entire transaction getting hold. Is there are anyway to make trigger run on separate session and after insert operation procedure runs without waiting for the trigger to complete.
Both procedure and the trigger are
PRAGMA AUTONOMOUS_TRANSACTION
You could try runnig the trigger part as dbms_job ... as follows:
CREATE OR REPLACE TRIGGER myrigger
AFTER INSERT
ON mytable
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
DECLARE
l_job number;
begin
dbms_job.submit( l_job, 'MYPACKAGE.MYFUNCTION(''' || :new.myField || ''');' );
END ;
/
If Trigger is based on insert operation, it will hold the current session, until that trigger action is completed. This is required to maintain integrity at database side. It may be possible to design a procedure & trigger in a better way if the requirements are known.

How to update a table using an AFTER INSERT trigger in that same table?

I have 2 triggers on a table A one is BEFORE INSERT and one AFTER INSERT :
CREATE OR REPLACE TRIGGER DEMO_TRG
AFTER INSERT
ON A
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
declare
PRAGMA AUTONOMOUS_TRANSACTION;
begin
UPDATE A
SET STATUS = 'DONE'
WHERE id_id =:new.p_id;
commit;
END;
/
Why the update command in the after insert doesn't work (the status is not set to DONE)? Did I missed something?
Most likely the issue is due to the AUTONOMOUS_TRANSACTION - when you do that, you're effectively switching to a different transaction, which won't know about your uncommitted transaction (ie. your insert), so there is nothing for it to update.
What you should do is amend the column (:new.status := 'DONE') in your before trigger. Or, even better, avoid triggers and have the logic in a stored procedure and don't allow anyone to directly insert into the table, although I appreciate this may be a big switch if you have lots of applications inserting directly into tables etc

Is there any data dictionary object in oracle to record the transaction details of triggers?

I have created trigger TEST_TRIG as below:
CREATE TRIGGER TEST_TRIG
AFTER INSERT ON TEST_TABLE
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
TEST_PROC();
END;
Procedure TEST_PROC code:
create or replace
PROCEDURE TEST_PROC
AS
BEGIN
EXECUTE IMMEDIATE 'truncate table TEST_FINAL';
INSERT INTO TEST_FINAL select * from TEST_TABLE;
commit;
END;
Initially, I disabled TRIGGER TEST_TRIG and inserted a record into TEST_TABLE and executed PROCEDURE TEST_PROC manually.
Output: I was able to fetch the same record what i inserted into TEST_TABLE from TEST_FINAL.
I flushed those records from both table and enabled the trigger TEST_TRIG.
Now when i inserts and commits the record in TEST_TABLE, I didn't found the record in TEST_FINAL table... I haven't received any error message also!!!
So I want to know whether trigger got fired or not?
I don't think you have fully grasped the implications of AUTONOMOUS_TRANSACTION. Effectively it means the code bounded by the pragma runs in a separate session . So, because of Oracle's read consistent isolation level, the autonomous transaction cannot see any of the data changes generated by the main transaction.
Thus, if TEST_TABLE is empty when you start the trigger will insert no rows into TEST_FINAL, regardless of how many rows you're inserting right now.
So: don't flush both tables. Insert some rows into TEST_TABLE and commit. TEST_FINAL will still be empty. Insert some more rows into TEST_TABLE and, lo! the first set of rows will appear in TEST_FINAL.
Obviously this is not the result you want. So you need to revisit your logic. It really doesn't make sense to truncate TEST_FINAL every time and definitely not FOR EACH ROW. That is Teh Suck! as far as performance goes. Likewise and for the same reason it doesn't make sense to populate the target table with INSERT ... SELECT .
Discarding the TRUNCATE means you don't need the pragma and everything becomes much simpler,
If you want to keep a history of the affected rows use something like this instead:
CREATE TRIGGER TEST_TRIG
AFTER INSERT ON TEST_TABLE
FOR EACH ROW
BEGIN
insert into test_final (col1, col2)
values (:new.col1, :new.col2);
END;
You'll need to change the exact code to fit your exact requirements.

How to create Oracle Trigger to record current SQL

I am currently doing a homework assignment and am getting stuck at a point.
I want to create a trigger for auditing, and Yes I do know FGA, but that's not what was asked.
My trigger needs to record the current SQL for auditing. This is what I have now.
Imagine I have my table already created to store the inserting value.
CREATE OR REPLACE TRIGGER ALL_SQL_AUDIT
AFTER UPDATE ON SCOTT.EMP
FOR EACH ROW
BEGIN
INSERT INTO ALL_SQL_AUDIT(TABLE_NAME, SQL_TEXT, SQL_TYPE, CHANGE_DATE, DB_USERNAME, OS_USERNAME)
SELECT 'SCOTT.EMP',
SYS_CONTEXT('USERENV','CURRENT_SQL'),
'UPDATE',
SYSDATE,
USER,
SYS_CONTEXT('USERENV','OS_USER')
FROM dual;
END;
/
Problem is SYS_CONTEXT('USERENV','CURRENT_SQL') never return anything, so does anyone know how to get the current DML that triggered this event?

Resources