Trigger in oracle. Update field when insert or update another field - oracle

I need To update the field DATAMARKER"of my table LOG_ALARMA when I have one INSTER or UPDATE of "CONTADOR".
i have this, but return muting error.
create or replace TRIGGER TRIGGER2
AFTER INSERT OR UPDATE OF CONTADOR ON LOG_ALARMA
for each row
BEGIN
UPDATE LOG_ALARMA a
SET a.DATAMARKER=(SYSDATE);
END;
I look another examples and they work but i can't execute this correctly.
IF i comment the line for each row in my trigger body then it is working fine but it UPDATES all the rows in my table.

You do not issue an update SQL statement, because that would again cause the trigger to fire.
Instead, you just set the value :new.DATAMARKER to sysdate, using PL/SQL not SQL.
Make it a BEFORE INSERT OR UPDATE also.

CREATE TABLE Mutating
(
ID1 NUMBER,
DATE1 DATE
)
data present in a table is
ID1 DATE1
1 09/01/2015 14:09:14
1 08/31/2015 14:09:21
2 08/30/2015 14:09:30
Now i want to update the date1 if any update happens on id1 column in that situation i have used trigger look below.
CREATE OR REPLACE TRIGGER Mutating_trg
before INSERT OR DELETE OR UPDATE ON Mutating
referencing old as old new as new
for each row
begin
if updating then
:new.date1:=sysdate;
end if;
end;
then i have issued update statement
update set Mutating id1=6 where trunc(date1)=trunc(sysdate-2)
1 row updated
Now look into results
ID1 DATE1
1 09/01/2015 14:09:14
6 09/02/2015 14:09:14
2 08/30/2015 14:09:30
You should use before statement.

Related

Create trigger that updates row depending on column value from other table

I would like to create a trigger that updates a row in a table (TABLE2) depending on column value from other table (TABLE1).
Which line must be updated depends on the ID of TBL1.
CREATE OR REPLACE TRIGGER INSERT_PAGE
BEFORE UPDATE OR INSERT
ON TABLE1
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO TABLE2 (TBL1ID,STEP,PAGE) VALUES
(:NEW.TBL1ID,:NEW.STEP,15);
ELSIF UPDATING and :NEW.STATE='APPROVED' THEN
UPDATE TABLE2
SET PAGE=16 AND STEP1='TEXT123'
WHERE TBL1ID =TABLE1.TBL1ID;
END IF;
END;
Can someone help me in creating a trigger with an update statement?
Would this be as well a good way to go?
So I have two tables, the column state in table1 is changing throughtout the process.
Depending on the change of the column state from table1, I want to change or better say update the row in table 2 and set some columns like PAGE and STATE in Table 2 depending on column value STATE in Table 1.
I do not want that a new row being created each time TABLE 1 gets updated, only the corresponding row should be updated.
As far as I understood is you want to update table2 only when the state in table1 changed to 'approved' for a row and if a row is inserted in table1 trigger will insert the row in table2.
I have made some corrections to your code. Let me know if it is not what you wanted.
CREATE OR REPLACE TRIGGER INSERT_PAGE
BEFORE UPDATE OR INSERT
ON TABLE1
FOR EACH ROW
DECLARE
BEGIN
IF INSERTING THEN
INSERT INTO TABLE2 (TBL1ID,STEP,PAGE) VALUES
(:NEW.TBL1ID,:NEW.STEP,15);
ELSIF UPDATING THEN
IF :NEW.STATE = 'APPROVED' THEN
UPDATE table2 t2 SET
STATE = :NEW.STATE, PAGE=16, STEP1='TEXT123'
WHERE t2.TBL1ID = :OLD.TBL1ID;
END IF;
END IF;
END;

Trigger to update week of the year

I want to write a trigger so that when decom_date is inserted or updated the week of the year is updated to the corresponding value.
This is what I have so far, but after inserting a date the week is still null.
create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
update check_decom set decom_week= (select to_char(to_date(decom_date,'DD-
MON-YY'),'WW') as week from check_decom) ;
end if;
end;
/
SQL> select * from check_decom;
DECOM_DATE DECOM_WEEK
------------------------------ ----------
23-JUN-17
What am I doing wrong?
Example for Week of a year
SQL> select to_char(to_date(sysdate,'DD-MON-YY'),'WW') as week from dual;
WE
--
28
You're doing a couple of things wrong, starting with date handling. Your decom_date column should be defined as a DATE column - it looks like it might be a string in your sample output. But your handling with sysdate is also wrong, as you're implicitly converting to a string in order to convert it back to a date, which is both pointless and prone to error as this might happen in a session which has different NLS settings. If your column is actually a DATE then you should not be calling to_date() against that either; and if it is a string then that conversion is valid but it should be a DATE.
Then your trigger is querying and trying to update the table that the trigger is against. With no data that doesn't error but doesn't do anything as there is no existing row to update - the one you are inserting doesn't exist yet. If there was data you would get a mutating table error, if you didn't get a too-many-rows exception from the select part.
Row-level triggers can access NEW and OLD pseudorecords to see and manipulate the affected row; you don't need to (and generally can't) use DML queries to access the data in the row you're manipulating.
If your table was defined with a date column and a number column:
create table check_decom(decom_date date, decom_week number);
then your trigger might look something like:
create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
:new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end if;
end;
/
although the if inserting check is a bit pointless as the trigger will only fire on insert anyway. Which in itself might be an issue; you perhaps want it to be set on update as well, but the logic the same, so would be:
create or replace trigger test_trigger
before insert or update on check_decom
for each row
begin
:new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end;
/
which does what you want:
insert into check_decom (decom_date) values (date '2017-06-23');
1 row inserted.
select * from check_decom;
DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17 25
But I wouldn't do this with a trigger at all. From Oracle 11g you can use a virtual column instead:
create table check_decom (
decom_date date,
decom_week generated always as (to_number(to_char(decom_date, 'WW')))
);
Table CHECK_DECOM created.
insert into check_decom (decom_date) values (date '2017-06-23');
1 row inserted.
select * from check_decom;
DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17 25

How to create a trigger which fires when any insert or update is done in a table?

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

TRIGGER Oracle to prevent updating or inserting

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

What do references to OLD evaluate to in the WHEN cause of an Oracle insert trigger?

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;

Resources