I have a problem with my database trigger in which I'm supposed to nullify the inserted/updated value (RESULTATOBT), although I need the OLD/NEW variables, so I can't apply this solution (updating the table in the table trigger).
The error is a mutating table one; due to modifying a table in a for each row trigger.
Here's the concerned extract of my code:
CREATE OR REPLACE TRIGGER VERIF_RESULTATS
AFTER INSERT OR UPDATE OF RESULTATOBT
ON PARTICIPATION
FOR EACH ROW
FOLLOWS VERIF_PARTICIPATION
WHEN ( NEW.RESULTATOBT IS NOT NULL )
BEGIN
UPDATE PARTICIPATION p
SET RESULTATOBT = NULL
WHERE p.CDPERS = :NEW.CDPERS
AND p.CDCOMPET = :NEW.CDCOMPET;
END;
/
Thank you in advance for your help.
N.B.: I'm a relatively new member, so I might require additional advices/edits if my question doesn't fit the proper format.
Use a before trigger and simply assign NULL:
CREATE OR REPLACE TRIGGER VERIF_RESULTATS
BEFORE INSERT OR UPDATE OF RESULTATOBT
ON PARTICIPATION
FOR EACH ROW
WHEN ( NEW.RESULTATOBT IS NOT NULL )
BEGIN
:new.RESULTATOBT := NULL;
END;
/
Related
How do i create a condition on oracle db? I'm new on this db.
I already create table called vehicle_parked, but i want to trigger vehicle number as NULL if parkedOnSite value is 'F' and the structure like this
vehicle_parked
- parked_id number(4) PK
- arrivalTime date
- parkedOnSite varchar(1) // value will be T/F
- vehicle_number varchar(8)
Thanks.
you can easily manipulate your data by creating a DML trigger that fires before your data is inserted into table, and changes data.
CREATE OR REPLACE TRIGGER trg_vehicle_parked
BEFORE INSERT OR UPDATE
ON vehicle_parked
FOR EACH ROW
DECLARE
BEGIN
if :new.parkedOnSite = 'F' then
:new.vehicle_number := null;
end if;
END;
/
In triggers, besides :new, we can use :old pseudo codes. They stand for the values of the columns before(:old) or after(:new) DML statements issued.
Especially for an update or delete trigger you may compare your column's old and new values in a trigger as in the example :
if ( nvl(:old.vehicle_number,0) != nvl(:new.vehicle_number,0) ) then
go_on_with_statement ....
Can I create an AFTER TRIGGER on a table and using that table in my SELECT query without getting mutating table error?
Example to a query I want to use.
This query will update number of times a certain status name is showing up in alert life cycle:
CREATE OR REPLACE TRIGGER COUNT_STEP
AFTER INSERT
ON STEPS
FOR EACH ROW
DECLARE
V_COUNT_SETP VARCHAR (10000);
BEGIN
SELECT COUNT (STATUS_NAME)
INTO V_COUNT_SETP
FROM (SELECT A.ALERT_ID, S.STATUS_NAME
FROM ALERTS A, ALERT_STATUSES S, STEPS ST
WHERE :NEW.ALERT_INTERNAL_ID = A.ALERT_INTERNAL_ID
AND ST.ALERT_STATUS_INTERNAL_ID = S.STATUS_INTERNAL_ID
AND S.STATUS_NAME IN ('Auto Escalate'))
GROUP BY ALERT_ID;
UPDATE ALERTS A
SET A.COUNT = V_COUNT_ESC
WHERE A.ALERT_INTERNAL_ID = :NEW.ALERT_INTERNAL_ID;
END;
/
The table I'm inserting a record to is also needed for counting the number of step occurrences since it's stores the alert id and all the steps id it had.
You need to be a bit more clearer in your questions. But, from what i understood, you need to create a trigger on a table, and perform a select for that same table. That gives you a mutanting table error. To bypass that, you need to perform a compound trigger on that table. Something like this:
create or replace trigger emp_ct
for insert on employees compound trigger
v_count number; -- Add variable here
before statement is
begin
-- PERFORM YOUR SELECT AND SEND TO A VARIABLE
end before statement;
after each row is
begin
-- DO WANT YOU WANTED TO DO. USE THE VARIABLE
end after each row;
end;
basically, with a compound trigger, you can capture every trigger event. By doing that, allows to query the table you're capturing.
I have created the below trigger, but it is not getting fired after i am doing new insert/update in to the mentioned table:
CREATE OR REPLACE TRIGGER ref_upd_user_phi_details
AFTER
INSERT OR UPDATE --of emp_email_address, ssn_nb
ON ref_adp_employees
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
UPDATE ref_adp_employees
SET emp_email_address = 'QA_' ||emp_email_address,
ssn_nb = nvl2(ssn_nb, NULL, '123-45-6789')
WHERE upper(emp_email_address) NOT LIKE 'QA_%'
AND upper(emp_email_address) LIKE '%#KEENAN.COM';
exception
WHEN others
THEN
NULL;
END;
Can someone please suggest me what i am missing?
As #phonetic_man pointed out, you are hiding any error you get by catching when others and taking no action. Without the exception block you would see that you are causing a mutating table error (ORA-04091), because you are referring to the same table the trigger is against.
If you took out the for each row part to turn it into a statement-level trigger then you would avoid that issue, but now you would have an infinite loop (ORA-00036) - when you try to update the table from within the trigger, that update itself causes the same trigger to fire again; which tries to update the same table yet again, which causes the trigger to fire yet again; etc. until Oracle notices and kills the process.
It would make more sense to use a before-insert row-level trigger to make sure the new values for the row match whatever pattern you are trying to enforce. Maybe something like:
CREATE OR REPLACE TRIGGER ref_upd_user_phi_details
BEFORE INSERT OR UPDATE --of emp_email_address, ssn_nb
ON ref_adp_employees
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
IF upper(:NEW.emp_email_address) NOT LIKE 'QA_%'
AND upper(:NEW.emp_email_address) LIKE '%#KEENAN.COM'
THEN
:NEW.emp_email_address := 'QA_' || :NEW.emp_email_address;
:NEW.ssn_nb := CASE WHEN :NEW.ssn_nb IS NULL THEN '123-45-6789' END;
END IF;
END;
/
And to see what it does:
insert into ref_adp_employees (emp_id, emp_email_address, ssn_nb) values (1, 'TEST_1', '123-45-6789');
insert into ref_adp_employees (emp_id, emp_email_address, ssn_nb) values (2, 'TEST_1#KEENAN.COM', '123-45-9876');
insert into ref_adp_employees (emp_id, emp_email_address, ssn_nb) values (3, 'QA_TEST_1', null);
select emp_id, emp_email_address, ssn_nb from ref_adp_employees;
EMP_ID EMP_EMAIL_ADDRESS SSN_NB
---------- ------------------------------ -----------
1 TEST_1 123-45-6789
2 QA_TEST_1#KEENAN.COM
3 QA_TEST_1
Not sure if you really intended to replace set SSNs with null, and turn nulls into the fixed value; I suspect you are really trying to replace set values with the fixed string and leaves nulls alone, in which case it would be:
:NEW.ssn_nb := CASE WHEN :NEW.ssn_nb IS NOT NULL THEN '123-45-6789' END;
You might also want to move that outside the IF block, so it's done regardless of the email address; I've replicated what your original code was trying to do but that might not be right.
If you have existing data that you want to modify to match these changes, do a one-off update of the whole table - don't try to do that inside a trigger.
Have you heard of Google? There's a myriad of answers and examples out there for triggers, but some things I see at this time:
1) Change trigger to BEFORE insert or update. Use AFTER when making changes to another table, or to run some subsequent process on the table.
2) Take out the comment to the individual fields being changed or added. That was good AFAIK.
3) In your body of the trigger use WHEN INSERTING and WHEN UPDATING. Or if you are just updating the table, change DDL to BEFORE UPDATE only.
4) In the update, reference with set :new.emp_email_address = 'QA_' || :old.emp_email_address ... and so on and so forth. That's where that old as old and new as new becomes important.
Kindly check if the trigger is valid or not by firing the below query..
SELECT *
FROM ALL_OBJECTS
WHERE OBJECT_NAME = trigger_name
AND OBJECT_TYPE = 'TRIGGER'
AND STATUS <> 'VALID'
The trigger is firing after update..
try before update
CREATE OR REPLACE TRIGGER ref_upd_user_phi_details
Before
INSERT OR UPDATE
I am having problems with this code below, which is a trigger used in Oracle SQL:
CREATE OR REPLACE TRIGGER TRG_TUTOR_BLOCK
BEFORE INSERT OR UPDATE ON tutors
FOR EACH ROW
DECLARE
BEGIN
IF :new.tutorName = :old.tutorName
THEN
RAISE_APPLICATION_ERROR(-20101, 'A tutor with the same name currently exists.');
ROLLBACK;
END IF;
END;
/
This trigger is used to prevent users from entering the same tutor name at different records.
After I insert two records with the same tutorname, the trigger does not block me from inserting it. Is there anyone can tell me what are the problems with this coding? Here are the sample format and insert values:
INSERT INTO tutors VALUES (tutorID, tutorName tutorPhone, tutorAddress, tutorRoom, loginID);
INSERT INTO tutors VALUES ('13SAS01273', 'Tian Wei Hao', '019-8611123','No91, Jalan Wangsa Mega 2, 53100 KL', 'A302', 'TianWH');
Trigger in Kamil's example will throw ORA-04091, you can see this with your own eyes here. ROLLBACK in a trigger is unnecessary, it runs implicitly when a trigger makes a statement to fail.
You can prohibit any DML on table by altering it with read only clause:
alter table tutors read only;
At last, integrity should be declarated with integrity constraints and not with triggers.
Good luck!
You don't need a trigger for this in Oracle.
You can do it with an "unique index" on the tutorName column (see http://docs.oracle.com/cd/B28359_01/server.111/b28310/indexes003.htm#i1106547).
Note: about your trigger, it fails on checking for another record with the same tutorName because it's not scanning the tutors table for another record with the same tutorName, it's just comparing the tutorName values of the row you are creating (in this case, old.tutorName is just NULL, because the row doesn't exist yet).
Check the case in yours trigger body
IF :new.tutorName = :old.tutorName
It returns true only if 'tutorName' value is the same in new and old record. When you'll trying to updat some value you'll get
IF 'someTutorName' = 'someTutorName'
which will return TRUE.
Inserting row cannot fire this rule because you're trying to compare something like that:
'someTutorName' = NULL
This case always returns FALSE.
Try to use something like that
CREATE OR REPLACE TRIGGER TRG_TUTOR_BLOCK
BEFORE INSERT OR UPDATE ON tutors
FOR EACH ROW
DECLARE
rowsCount INTEGER;
BEGIN
SELECT COUNT(*) FROM tutors WHERE tutorName is :new.tutorName INTO rowsCount;
IF rowsCount > 0
THEN
RAISE_APPLICATION_ERROR(-20101, 'A tutor with the same name currently exists.');
ROLLBACK;
END IF;
END;
/
But the best solution is the one mentioned by friol - use unique index by executing SQL like this
ALTER TABLE tutors
ADD CONSTRAINT UNIQUE_TUTOR_NAME UNIQUE (tutorName);
If you wanna completely ignore recording a row to a table you can follow these steps
rename table to something else and create a view with the same name and create an instead of trigger.
create table usermessages (id number(10) not null)
GO
alter table usermessages rename to xusermessages
GO
create or replace view usermessages as (select * from xusermessages)
GO
create or replace trigger usermessages_instead_of_trg
instead of insert or update on usermessages
for each row
begin
Null ;
end ;
GO
insert into usermessages(123)
Live test available here below
http://sqlfiddle.com/#!4/ad6bc/2
When writing a row-level trigger in Oracle, I know that you can use the OLD and NEW pseudo-records to reference the old and new state of the row that fired the trigger. I know that in an INSERT trigger OLD doesn't contain any data, but I'm not sure how this affects the evaluation of a WHEN clause for that trigger. For example, if I have the following trigger:
CREATE OR REPLACE TRIGGER mung_row
BEFORE INSERT OR UPDATE ON some_table
FOR EACH ROW
BEGIN
:NEW.foo = 'some val';
END;
and I want to modify this trigger to only run on an update when foo was previously null, but always run on an insert, I could satisfy the update part of the change by adding a WHERE clause:
CREATE OR REPLACE TRIGGER mung_row
BEFORE INSERT OR UPDATE ON some_table
FOR EACH ROW
WHEN (OLD.foo IS NULL)
BEGIN
:NEW.foo = 'some val';
END;
Will this cause problems in the insert case? What will OLD.foo evaluate to in the INSERT?
I'm aware that I could split the INSERT and UPDATE triggers or use INSERTING/UPDATING/DELETING in the trigger body, but I'd rather not in the case that inspired this question.
When a record is being inserted, every field of OLD will be NULL, including the fields marked as NOT NULL in the table's definition.
For example, suppose your table has a non-nullable column named id:
CREATE TABLE some_table (
id NUMBER NOT NULL,
foo VARCHAR2(100)
)
When a record is inserted into this table, OLD.id will be NULL. However, when a record is updated in this table, OLD.id will not be NULL. Because you only want to change :NEW.foo if a record is being updated, you just have to check to see if OLD.id has a non-null value.
CREATE OR REPLACE TRIGGER mung_row
BEFORE INSERT OR UPDATE ON some_table
FOR EACH ROW
WHEN (OLD.id IS NOT NULL AND OLD.foo IS NULL)
BEGIN
:NEW.foo = 'some val';
END;