update multiple table with the same trigger DB Oracle - oracle

i'm creating a trigger, for ibm maximo application, that has to start when the field mens_ack is updated;
when that happens, the 'status' field must become of a certain value
after that i have to update another table (longdescription table) based on the relationship workorderid=ldkey
create or replace TRIGGER "MAXIMO"."CHANGE_MENS_MAINT_T"
AFTER UPDATE OF MENS_ACK ON WORKORDER
BEGIN
update workorder
set status='SCHED', statusdate= sysdate
where mens_ack='1' and status!='SCHED';
update longdescription
set ldtext= concat(ldtext, 'scheduled maintenance - '+sysdate+' ')
where ldkey = ????;
END;
I can't use NEW and OLD in this trigger, so i doesn't know how to take the WORKORDERID (the key on which the relation is based) in order to specify what record i have to find in longdescription table
can anyone help me?

You could use the RETURNING INTO clause from the first update.
https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm
update workorder
set status='SCHED', statusdate= sysdate
where mens_ack='1' and status!='SCHED'
returning workorderid into v_workorderid;
Watch out for the number of updated workorders, since the v_workorderid might have to be declared as an array.

Related

Increment new column after insert

I have a question for all of you. I'm quite new in SQL and searched for more than 2 hours and didn't find exactly what I need.
I'm having a table in SQL named Courses. Here is the constructor:
CREATE TABLE Courses
(sign VARCHAR2(6) NOT NULL,
title VARCHAR(50) NOT NULL,
credits INTEGER NOT NULL,
CONSTRAINT PrimaryKeyCourses PRIMARY KEY (sign)
);
I have to add a new column, which I did with :
ALTER TABLE Courses ADD frequency INTEGER;
I want to create a trigger which will increment every time a new courses is added.
I tried to do this :
CREATE TRIGGER fq
AFTER INSERT ON Courses
FOR EACH ROW
UPDATE frequency SET frequency = frequency + 1;
But it doesn't seems to work properly :( I don't know what to do.
No need to use an UPDATE statement, use a SELECT statement with max(value)+1. And to be able to change a :new. value, need to convert trigger to BEFORE type.
So, you can use the one as below
CREATE OR REPLACE TRIGGER fq
BEFORE INSERT ON Courses
FOR EACH ROW
DECLARE
BEGIN
select nvl(max(frequency),0)+1
into :new.frequency
from Courses;
END;
Of course you need a commit after a DML statement, I think it's better to include only one commit outside of this trigger after INSERT statement applied on Courses table, because of providing transaction integrity rule.
P.S. I know you're restricted to use a trigger, but Using a sequence for the value of column frequency is a better, practical alternative as #nikhil sugandh suggested. In this case a trigger is not needed. If you're using DB version 12c, you can add that sequence as default for the column frequency as frequency INTEGER GENERATED ALWAYS AS IDENTITY during the table creation.
use sequence :
CREATE SEQUENCE Courses_frequency
MINVALUE 1
MAXVALUE 999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
and do insert like:
INSERT INTO Courses
(sign,title,credits,frequency)
VALUES
(value1,value2,value3,Courses_frequency.NEXTVAL);

Insert in Merge not working in Oracle

I am new to Oracle. I have a table in Oracle which has 4 columns Period, Open_Flag,Creation_Dt,Updated_By.
The Period column is the Primary key of the table. I have created a proc which will check the value of period from input parameter in the table, if its existing, the value of Open_flag has to be updated else a new record shall be inserted.
create or replace
PROCEDURE PROC_REF_SAP_PERIOD(
V_PERIOD IN NUMBER,V_OPEN_FLAG IN VARCHAR2,V_CREATION_DT IN DATE,V_UPDATED_BY IN VARCHAR2)
AS
BEGIN
MERGE INTO REF_SAP_PERIOD T
USING (SELECT * FROM REF_SAP_PERIOD WHERE PERIOD=V_PERIOD )S
ON (T.PERIOD=S.PERIOD )
WHEN MATCHED THEN UPDATE SET OPEN_FLAG = V_OPEN_FLAG --WHERE PERIOD=V_PERIOD AND CREATION_DT=V_CREATION_DT AND UPDATED_BY=V_UPDATED_BY
WHEN NOT MATCHED THEN INSERT (PERIOD,OPEN_FLAG,CREATION_DT,UPDATED_BY) VALUES (V_PERIOD,V_OPEN_FLAG,V_CREATION_DT,V_UPDATED_BY);
END;
The issue is that the Update is working well in this case, however, the insert is not working. Please help.
You are merging table with itself, filtered by period. Obviously, it will never see your non-existent values in itself.
Try this line instead of your USING line:
using (select V_PERIOD "period" from dual)S

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

How can i insert a variable value into a column of table using trigger and sequence for oracle 10g db

Am developing an application which helps people plan there schedule.
Lets say i have a table called 'Plan_Table' in which there are columns like
id,user_name, timestamp,place,event,plan_number.
For each day, a person can insert many records depending on his activities. I want 'plan_number' column to be populated by a trigger.
Suppose an user inserts five records at a time(in a batch). I want the plan_number field to be inserted as
plan_1
plan_1
plan_1
plan_1
plan_1
if he comes up with another plan.. and does few inserts, lets say 3 this time... I want the plan_number field to be inserted as
plan_2
plan_2
plan_2
How to achieve this using trigger and sequence?
Thanks in advance.
I think you can use the combination of the before statement level trigger for that table along with the global package variables and then use them in the Row Level trigger for that table.
Hope it gives you a heads up with the above logic
var_plan_number number := 0;
begin
if :new.plan_number is null then
select max(plan_number) into var_plan_number from plan_table where timestamp < CURRENT_TIMESTAMP - 5 --*some_treshold - ie 5 seconds*
and timestamp > CURRENT_TIMESTAMP and timestamp > trunc(sysdate) and user_name = :new.user_name;
--idea is to select max plan_number for current day and increment it by 1
--treshold should be set to time, your script is able to process batch records
var_plan_number := var_plan_number + 1;
:new.plan_number := var_plan_number;
end if;
that should do the trick...
Please consider this as a pseudo code, how your trigger should look like. There is no need for sequences.
The problem lies in the definition of "at a time (in a batch)". It will be difficult to tell the trigger when one batch ends and when a new one begins. It is possible with package variables, but the most competent place is your application.
I'd create a sequence to generate the ids, but pick up the ids in your application and feed them directly to the INSERT statement:
CREATE SEQUENCE myids;
CREATE TABLE plan_table(id int, user_name varchar2(30), mytimestamp, ...);
And in your code:
SELECT myids.nextval INTO myplanid FROM DUAL;
INSERT INTO plan_table(myplanid, myuser_name, SYSTIMESTAMP, place1 ...);
INSERT INTO plan_table(myplanid, myuser_name, SYSTIMESTAMP, place2 ...);
INSERT INTO plan_table(myplanid, myuser_name, SYSTIMESTAMP, place3 ...);
COMMIT;
Thanks for the answers you provided me. You really let me think in a purely db perspective.
As a web application developer, I thought, its a much better approach to use sequence/trigger to help me out with this problem. However, I found the solution from business logic of Application itself.
I am using Hibernate ORM for managing db tables. Hence i pulled out the max value of plan number using the following pieces of code.
Session session = getSessionFactory().openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(Mwwp_Plan.class).setProjection(Projections.max("plan_number"));
Integer maxPlanNumber = (Integer) criteria.uniqueResult();
session.getTransaction().commit();
System.out.println(maxPlanNumber);
if(maxPlanNumber==null)
{
System.out.println("maxPlanNumber is null");
maxPlanNumber = 0;
}
else
{
}
System.out.println("maxPlanNumber:"+maxPlanNumber);
return maxPlanNumber;
This is inside a function which my app uses to get the max(plan_number). If there is no plan_number in the table. It will give a default of 1.
Note: Mwwp_Plan is the name of table i used in my application.
Hence I achieved what i wanted.
Thanks for your help.

Oracle after update trigger not performing correctly

I have two tables, tblapplication and tblapplicationhistory. tblapplicationhistory is an archive of every change made to the status of applications in the application table. A student in the application table can have many applications.
When an application status becomes "Offer accepted", the status ID is set to 7. This is then reflected in both the application and applicationhistory table. At this point, all other application statuses for the given student should be set to 8, "Offer rejected".
create or replace
TRIGGER trg_declineapplications AFTER UPDATE ON tblapplicationhistory FOR EACH ROW
BEGIN
IF :NEW.statusid_fk_nn = 7 THEN
UPDATE tblapplication
SET statusid_fk_nn = 8
WHERE studentrecordnumber_fk_nn = ( SELECT studentrecordnumber_fk_nn
FROM tblapplication
WHERE applicationid_pk_nn = :NEW.applicationid_fk_nn
)
AND applicationid_pk_nn != :NEW.applicationid_fk_nn;
END IF;
END;
The trigger is compiled without errors, and the trigger activates without returning any SQL errors, but performs no computation on any rows in the application table. There must be an error in the logic of the trigger in that case, but I do not see it.
To my mind, if the updated row in tblapplicationhistory contains statusID 7, then an update is performed on the application table, setting statusID to 8 for every application belonging to the same student other than the accepted application.
More information can be given if required.
Table definitions:
tblapplication:
applicationid_pk_nn
studentrecordnumber_fk_nn
jobid_fk_nn
statusid_fk_nn
tblapplicationhistory:
applicationid_fk_nn
statusid_fk_nn
datechanged_nn
applicationhistoryid_pk_nn
In tblapplication, the primary key is applicationid_pk_nn and all other field are foreign keys.
In tblapplicationhistory, applicationhistoryid_pk_nn is the primary key. statusid_fk_nn is retreived from tblapplication with applicationid_fk_nn.
The trigger method does not look very robust.
How about when you update the records to set the application accepted/rejected you do something like this:
update my_table
set status_id = case my_table.application_id
when application_id_for_accepted_offer then 7
else 8
end
where student_id = student_id_to_update;

Resources