I have requirement wherein I need to get the affected row if a row gets updated or added. I have seen many examples wherein we can use :new or :old keywords to get the columns e.g. new.columnName but is there a way to get the complete row. Code snippet is as below. Thanks in advance.
CREATE OR REPLACE TRIGGER TRG_134673016571507516045
AFTER
INSERT OR UPDATE ON employees
FOR EACH ROW
DECLARE
content varchar2(4000) := '||:NEW.row||';
BEGIN
///////
END;
Related
Trigger under question is for Table which has ETL in ODI but user also has option to edit certain **columns **
if they want to adjust them. This is done using APEX
Trigger is used to change two columns : Changed_by and Change_on.
Both indicating Changes done on APEX PAGE only.
The issue comes when ODI load is run and is MERGE INSERT UPDATE , Trigger thinks its updating and changes the above two columns to "NULL" as its a manual update done by ODI and not on APEX.
Solution
For each Editable Column, there should be a logic which checks NEW: <> :OLD, but as i have 15 columns need to write a lot of code.
Are there others way to achieve this ?
create or replace TRIGGER DW.TRG BEFORE
UPDATE ON DW.TABLE
REFERENCING
NEW AS new
OLD AS old
FOR EACH ROW
BEGIN
IF updating THEN
SELECT
SYSDATE,
v('APP_USER')
INTO
:new.changed_on_dt,
:new.changed_by
FROM
dual;
END IF;
END;
Check if an apex session exists for the current database session and only execute when it is the case.
create or replace TRIGGER DW.TRG BEFORE
UPDATE ON DW.TABLE
REFERENCING
NEW AS new
OLD AS old
FOR EACH ROW
BEGIN
IF SYS_CONTEXT('APEX$SESSION','APP_SESSION') IS NOT NULL AND updating THEN
:new.changed_on_dt := SYSDATE;
:new.changed_by := SYS_CONTEXT('APEX$SESSION','APP_USER');
END IF;
END;
Notes
avoid the SELECT FROM DUAL, you can just assign the values in the trigger.
The "V" functions are pretty slow. For a while there have been sys_context settings that store the session and user data. Those are a lot faster than a function call to the "V" function.
You could make it so that it never overwrites a non-null value with a null one:
IF v('APP_USER') IS NOT NULL
THEN
:new.changed_by := v('APP_USER');
:new.changed_on_dt := SYSDATE;
END IF;
I am required to have before/after image statement for every update /insert operation done on a table in DB in order to properly record the before /after image in the spool file of the script.
I am not sure how to do this like example for this query :
update employee set divison = 'IT' where empId = 2223;
Any help would be appreciated.
if I understand Your question correctly, I would use table triggers.
You have option to write code that executes before and after insert/update statament.
Since update command is complex, you have both images, "BEFORE" and "AFTER" (data did exist before update and exists after update). So, I would write trigger that executes BEFORE update, and that collects all the :OLD data (this notation is used for table fields before data is changed using update command) and wrote them to the output (or insert them into some kind of history table for later audit). Also I would write another trigger that is executed AFTER update and do the same thing with :NEW data (wrote to output or something else).
I think that for insert is trivial, you don't have "BEFORE" image, only "AFTER" so You can write AFTER trigger, as for update command.
I hope that You can understand my answer.
To add some code here:
CREATE OR REPLACE TRIGGER BU_EMP
BEFORE UPDATE
ON EMP
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('BEFORE: '||:OLD.EMP_ID||' '||:OLD.EMP_NAME||' '||:OLD.DEPARTMENT);
EXCEPTION
WHEN OTHERS THEN RAISE;
END;
And, similar:
CREATE OR REPLACE TRIGGER AU_EMP
AFTER UPDATE
ON EMP
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('AFTER: '||:NEW.EMP_ID||' '||:NEW.EMP_NAME||' '||:NEW.DEPARTMENT);
EXCEPTION
WHEN OTHERS THEN RAISE;
END;
And now, if You have record with EMP_ID=2233, after update You will have two dbms_output lines, one with data BEFORE, and one with data AFTER update command.
Best regards,
Aleksandar
It sounds like you just want to select from the table before and after the update.
-- Before
SELECT *
FROM employee
WHERE empId = 2223;
--Change
UPDATE employee
SET division = 'IT'
WHERE empId = 2223;
-- After
SELECT *
FROM employee
WHERE empId = 2223;
I have a trigger:
create or replace trigger trig
before insert on sistem
for each row
declare
v_orta number;
begin
SELECT v_orta INTO :new.orta_qiymet
FROM sistem;
v_orta:=(:new.riyaziyyat+:new.fizika)/2;
insert into sistem(orta_qiymet)
values(v_orta);
end trig;
When I insert a row:
insert into sistem(riyaziyyat,fizika) values(4,4)
I get an error:
Why am I getting that error?
This is fundamentally not understanding how triggers work. You can't generally select from the table the trigger is against, and a before-insert trigger shouldn't not insert into the same table again - as that would just cause the trigger to fire again, infinitely (until Oracle notices and stops it). You aren't even currently using the v_orta value you're attempting to query.
I suspect you think the trigger is instead of your original insert perhaps, and really you want to set the orta_qiymet value in the newly-inserted row automatically based on the other two columns you have supplied. To do that you don't (and can't) select those values; instead you refer to the :NEW pseudorecord as you are already doing, and then set the third column value in that same pseudorow:
create or replace trigger trig
before insert on sistem
for each row
begin
:new.orta_qiymet := (:new.riyaziyyat + :new.fizika)/2;
end trig;
/
There is a lot of information in the documentation; this is similar to one of the examples.
I created the trigger to update the oracle data base table after insert.
CREATE OR REPLACE TRIGGER Update_ACU
AFTER INSERT ON TBL_ACU
FOR EACH ROW
BEGIN
UPDATE TBL_ACU
SET CURRENCY = 'XXX'
WHERE ACCOUNT like '%1568';
END ;
I inserted record as
insert into TBL_ACU values('23','USD','1231568');
I am getting table ORACLE Mutating trigger error.
Please help me how to resolve this.
It would be better to use BEFORE INSERT trigger to do this.
Try like this,
CREATE OR REPLACE
TRIGGER update_acu
BEFORE INSERT ON tbl_acu
FOR EACH ROW
WHEN (NEW.ACCOUNT LIKE '%1568')
BEGIN
:NEW.currency := 'XXX';
END ;
Well, you cannot modify the table from the trigger if the trigger is called upon modification of that table. There are various solutions to this problem including an AFTER STATEMENT trigger and caching modifications in some collection defined in PL/SQL PACKAGE, howewer in your situation I'd rather change the body of your trigger to this:
BEGIN
IF :NEW.ACCOUNT LIKE '%1568' THEN
:NEW.CURRENCY := 'XXX';
END IF;
END;
You can use the :NEW and :OLD variables inside the trigger, which identify the new and old values of the record accordingly. Modifying values of the :NEW record will cause changes in data actually inserted to the database.
The below code is giving a mutating error.
Can any1 pls help in solving this.
CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger
BEFORE INSERT
ON aso.aso_quote_headers_all
FOR EACH ROW
BEGIN
UPDATE aso.aso_quote_headers_all
SET quote_expiration_date=sysdate+90
where quote_header_id=:new.quote_header_id;
END;
/
In oracle there are two levels of triggers: row level and table level.
Row level triggers are executed for each row. Table level triggers executed per statement, even if a statement changed more then one row.
In a row level trigger, you cannot select/update the table itself that has the trigger: you will get a mutating error.
In this case, there is no need for an UPDATE statement. Just try this:
CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger
BEFORE INSERT
ON aso.aso_quote_headers_all
FOR EACH ROW
BEGIN
:new.quote_expiration_date=sysdate+90;
END;
/
EDIT Rajesh mentioned it is possible, that before inserting a new row, OP wants to update all other records in the aso_quote_headers_all table.
Well, this is feasible, but it's a little tricky. To do this properly, you will need
A pl/sql package and a variable in the package header that is modified by the triggers. This variable could be a list holding the IDs of newly inserted records. Row level after insert trigger would add a new ID to the list. The content of this package variable will be different for each different session, so let's call this variable session_variable.
Row level after insert trigger, that would add new ID to the session_variable.
Table level after insert trigger that would get IDs from the session_variable, process the ID and then remove it from the session_variable. This trigger could execute necessary selects/updates on the aso_quote_headers_all. After a newly inserted ID is processed, this trigger should make sure it gets removed from the session_variable.
I realise you must have resolved your issue by now. However I am adding this answer below to help anyone else facing similar problem as you and I faced.
I recently encountered mutating table (ORA-04091: table XXXX is mutating, trigger/function may not see it) issue and after searching around realised the Compound Triggers feature available in 11g. If you're on 11g following compound trigger would have solved your issue.
CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger
FOR INSERT ON aso.aso_quote_headers_all
COMPOUND TRIGGER
row_id rowid;
AFTER EACH ROW IS
BEGIN
row_id := :new.rowid;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
UPDATE aso.aso_quote_headers_all
SET quote_expiration_date = sysdate+90
WHERE rowid = row_id;
END AFTER STATEMENT;
END aso_quote_cuhk_trigger;
/
A word about how it works. This compound trigger fires 2 events :
First is AFTER EACH ROW where we capture the rowid of newly inserted row
Next is AFTER STATEMENT where we update the table using rowid (captured during first event) in the WHERE clause.
A useful link if you want to read more about Compound Triggers.