How to create Oracle Trigger to record current SQL - oracle

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?

Related

How to look at the table whose insertion fired the trigger?

I have a table of bids and everytime a bid is added in an auction I want to create new notifications to every bidder in that auction. As this is for a class of databases I though of doing a trigger to show some skills in oracle pl/sql.
My trigger is like this:
CREATE OR REPLACE TRIGGER create_notifs
AFTER INSERT ON bid
FOR EACH ROW
BEGIN
INSERT INTO notification(id_notif, id_auction, username, time, seen_state)
SELECT notif_id_seq.NEXTVAL, :NEW.id_auction, username, SYSDATE, 0
FROM bid
WHERE bid.id_auction = :NEW.id_leilao;
END;
/
Now this trigger won't work because it's accessing the table that fired it. It is not a problem though because I'm not changing it and it really needs to be after the insertion because I need to see if it passes the constraints. How can I do this?
You can't do a SELECT from the table on which a row trigger is declared or you get the dreaded "mutating table" error, but it doesn't look to me like you need to SELECT anything. Try rewriting your trigger as:
CREATE OR REPLACE TRIGGER create_notifs
AFTER INSERT ON bid
FOR EACH ROW
BEGIN
INSERT INTO notification
(id_notif, id_auction, username, time, seen_state)
VALUES
(notif_id_seq.NEXTVAL, :NEW.id_auction, username, SYSDATE, 0);
END;
Best of luck.

Oracle_Trigger: Auto Update Of a Column Based Upon INSERT/UPDATE

This might appear a simple query for most of you, but I am a beginner in Oracle DB.
A table has been created with below script-
CREATE TABLE PLAN_TABLE
(
PL_ID DECIMAL(10,0) PRIMARY KEY NOT NULL
,PL_NAME VARCHAR2(300) DEFAULT NULL
,UPDATED_TS TIMESTAMP DEFAULT SYSDATE NOT NULL
,DELETE_FLAG DECIMAL(10,0) DEFAULT 0 NOT NULL
);
The requirement is to have SYSDATE for UPDATED_TS for any new record inserted into the table and also in case when the DELETE_FLAG is updated to 1. Can it be done by trigger?
The below trigger was created-
CREATE OR REPLACE TRIGGER PT_BEFORE_INSERT_TR
BEFORE INSERT ON PLAN_TABLE
FOR EACH ROW
BEGIN
SELECT SYSDATE INTO :new.UPDATED_TS FROM DUAL;
dbms_output.put_line('Inserted');
END;
/
Below error was encountered while inserting record into the table-
error: ORA-04091: table I60_SCH04.PLAN_TABLE is mutating, trigger/function may not see it
Can you please help in letting me know that where am I committing the mistake? Is there any better way to achieve the requirement based upon INSERT/UPDATE?
The actual error you get is due to the fact that you try to select from a table that you actually are changing. To prevent the issue there are a couple of methods, but in you case things are really simple.
SYSDATE is a function, that you could call directly inside PL/SQL block (which a trigger actually is) and use the value returned to update the set the column value
CREATE OR REPLACE TRIGGER PT_BEFORE_INSERT_TR
BEFORE INSERT ON PLAN_TABLE
FOR EACH ROW
BEGIN
:new.UPDATED_TS := sysdate;
dbms_output.put_line('Inserted');
END;
/
OK, this covers the insert part.
For updating - once again, many options. One could be - change your trigger to BEFORE INSERT OR UPDATE ON PLAN_TABLE.
In this case whenever you issue update or insert - this trigger is fired for each row and updates the date column accordingly.
And of course you could use particular checks available in triggers, something like
IF INSERTING OR UPDATING('DELETE_FLAG') THEN
...
END IF;
and code in the logic you need.

Reverse a commit value in oracle sql

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.

Create Oracle Trigger to execute PL/SQL program when row is inserted to table

I want to create a trigger in Oracle 11g, that is fired when a row is inserted to the table DLGPROD.INV_CHEMICAL when the value for the BATCHTYPE column is equal to 'STANDARD'.
The trigger will execute a PL/SQL program called SYS.STDEMAIL
When I try to call the STDEMAIL program, I get PLS-00331 illegal reference.
I am pretty new to working with triggers or PL/SQL, and I can't figure out how to tell the trigger #1 - to only fire when a row is updated AND the BATCHTYPE column value is 'STANDARD', and #2 - how to correctly call the PL/SQL program called STDEMAIL belonging to the SYS schema.
Any assistance would be greatly appreciated.
From the docs (http://docs.oracle.com/cd/B10501_01/appdev.920/a96590/adg13trg.htm)
#1 Here you can see that Emp_tab is the table you are watching, and Sal is a column. Using the new keyword as in new.Sal you can check the new inserted value.
CREATE OR REPLACE TRIGGER Log_salary_increase
AFTER UPDATE ON Emp_tab
FOR EACH ROW
WHEN (new.Sal > 1000)
BEGIN
INSERT INTO Emp_log (Emp_id, Log_date, New_salary, Action)
VALUES (:new.Empno, SYSDATE, :new.SAL, 'NEW SAL');
END;
#2 You can use the call keyword to execute an existing procedure
CREATE OR REPLACE TRIGGER logontrig AFTER LOGON ON DATABASE
-- Just call an existing procedure. The ORA_LOGIN_USER is a function
-- that returns information about the event that fired the trigger.
CALL foo (ora_login_user)
/

Oracle APEX Trigger - Can I affect 'Table A' when I execute a trigger on the insert of 'Table B'?

OK guys, here is my problem. I am trying to create a Trigger in Oracle APEX that will insert the 1st row on table 'APEX_LOGS' with the default values spelled out below when I submit a row for table 'MAIN_APEX'. Here is the trigger I am trying to run:
CREATE OR REPLACE TRIGGER "DEFAULT_LOG_ENTRY" AFTER insert on "MAIN_APEX" for each row
begin
:new.APEX_LOGS.LOG_ENTRY:= 'This log page was established. Actions and communcations are captured from this date and time onward.';
:new.APEX_LOGS.LOG_DATE:= sysdate();
:new.APEX_LOGS.CIRCULATION:= 'External';
:new.APEX_LOGS.MAIN_PK_REF:= &MAIN_APEX.MAIN_PK;
:new.APEX_LOGS.TECHWRITER:= &MAIN_APEX.TECHWRITER;
end;
Thoughts? This topic seems to be incredibly poorly documented. Even the 'Help' section gives no insight into proper formatting. Thanks guys.
You are confusing Apex and database concepts: triggers are part of the database, not of Apex.
The syntax for the trigger would be:
CREATE OR REPLACE TRIGGER "DEFAULT_LOG_ENTRY" AFTER insert on "MAIN_APEX"
for each row
begin
insert into apex_logs (log_entry, log_date, circulation,
main_pk_ref, techwriter)
values ('This log page was established. Actions and communcations are captured from this date and time onward.'
, sysdate
, 'External'
, :new.main_pk
, :new.TECHWRITER);
end;

Resources