Need to create a trigger - sql

select id, status, name , status_change_dt from account;
whenever status changes to any other status status_change_dt should be updated to sysdate
create or replace
TRIGGER ADD_DT
after UPDATE of status ON account
for each row
BEGIN
:new.status_change_dt := sysdate ;
END;
I am getting error in creating this trigger. Thank you in advance.

You can't change the new value after the update.
Even error is pretty clear on this:
ORA-04084: cannot change NEW values for this trigger type
Use BEFORE instead of AFTER.
Try this:
create or replace
TRIGGER ADD_DT
before UPDATE of status ON account
for each row
BEGIN
:new.status_change_dt := sysdate ;
END;
EDIT:
If you have another table
account_dtl (ref_id references account(id), status_2);
And account table has one more column to keep track of status_2 changes, use this:
create or replace
TRIGGER ADD_DT_Status_2
before UPDATE of status_2 ON account_dtl
for each row
BEGIN
update account
set status2_change_dt := sysdate
where id = :new.ref_id;
END;
Although it would make more sense to keep track of status_2 changes in its own table i.e. account_dtl

Related

trigger to update specific column when insert/update happened in same table

I trying to write a trigger that will update a column when user insert or updates a row, within the same table.
Example:
insert into user(ID, F_NM, L_NM, EMAIL) values ('1', 'John','Doe','john.doe#market.org.com');
after the insert, i want to call: update user set ORG = 'market' where ID = '1'.
create or replace trigger user_change
after insert or update of EMAIL on USER
for each row
declare
NEW_ORG VARCHAR(10);
BEGIN
CASE
when :NEW.EMAIL like '$#market.org.com' then
NEW_ORG := 'market';
........
END CASE;
UPDATE USER set ORG = NEW_ORG where ID = :NEW.ID
END;
Calculating the new ORG work, but I can't get the update statement to work.
I get 'ORA-04091 table USER is mutating, trigger/funtion may not see it', figure its due to me inserting/updating the same record at same time. Tried adding 'pragma autonomous_transaction' and 'commit' to the trigger, the insert/update of fields works but the ORG does not get updated.
Also tried changing to INSTEAD OF INSERT OR UPDATE OF EMAIL but I keep getting 'ORA-04073 column list not valid for this trigger type'
create or replace trigger user_change
instead of insert or update of EMAIL on USER
while i get 'ORA-25002 cannot create instead of triggers on tables'
create or replace trigger user_change
instead of insert on USER
Why not simply turn the trigger to a before trigger, when you can set the value before it is written? This way, you don't need to run a new DML statement on the table, which avoid the "mutating" error.
create or replace trigger user_change
after insert or update of email on user
for each row
begin
if :new.email like '%#market.org.com' then
:new.org := 'market';
end if;
end;
Looks like your org column can be calculated virtual column. In this case it would be better to create user-defined deterministic pl/sql function that returns correct calculated value and add it to your table, for example:
Alter table t add org varchar2(30) generated always as (f_get_org(email))

PL/SQL ORACLE: Trigger updates on delete

I am trying to make a trigger that increases the booked value and decreases the available value whenever new record is inserted inside the table ticket_price. If a record is deleted, I want it to decrease the booked value and increase the available value.
Although I am able to successfully make the trigger work for INSERT, I am unable to do the same for updating the values on deletion of a record.T his is the error I get whenever I try to delete a record
ORA-01403: no data found
ORA-06512: at "K.CAL", line 6
ORA-04088: error during execution of trigger 'K.CAL'
Just to clarify, I am updating values in another table, not the same table I am deleting!
Here is my code for the trigger:
CREATE OR REPLACE TRIGGER cal
BEFORE INSERT OR DELETE ON TICKET_PRICE FOR EACH ROW
DECLARE
V_TICKET TICKET_PRICE.TICKETPRICE%TYPE;
V_BOOKED FLIGHTSEAT.BOOKED_SEATS%TYPE;
V_AVAILABLE FLIGHTSEAT.AVAILABLE_SEATS%TYPE;
BEGIN
SELECT BOOKED_SEATS,AVAILABLE_SEATS
INTO V_BOOKED,V_AVAILABLE
FROM FLIGHTSEAT
WHERE SEAT_ID=:NEW.SEAT_ID;
IF INSERTING THEN
V_BOOKED:=V_BOOKED+1;
V_AVAILABLE:=V_AVAILABLE-1;
UPDATE FLIGHTSEAT
SET BOOKED_SEATS=V_BOOKED, AVAILABLE_SEATS=V_AVAILABLE
WHERE SEAT_ID=:NEW.SEAT_ID;
ELSIF DELETING THEN
V_BOOKED:=V_BOOKED-1;
V_AVAILABLE:=V_AVAILABLE+1;
UPDATE FLIGHTSEAT
SET BOOKED_SEATS=V_BOOKED, AVAILABLE_SEATS=V_AVAILABLE
WHERE SEAT_ID=1;
END IF;
END;
You have correctly surmised that :new.seat is not available on the update for a delete. But neither is it available for the select and ow could you know sea_id=1 was need to be updated? For reference to Deleted row data use :Old.column name; is this case use :old_seat_id for both select and update.
But you don't need the select at all. Note: Further you have an implied assumption that seat_id is unique. I'll accept that below.
create or replace trigger cal
before insert or delete on ticket_price
for each row
declare
v_seat_id flightseat.seat_id%type;
v_booked flightseat.booked_seats%type;
begin
if INSERTING then
v_booked := 1;
v_seat_id := :new.seat_id;
else
v_booked := -1;
v_seat_id := :old.seat_id;
end if;
update flightseat
set booked_seats=booked_seats+v_booked
, available_seats=available_seats-v_booked
where seat_id = v_seat_id;
end;

Creating a Trigger in Oracle

I am trying to create a trigger in Oracle SQLPlus. The trigger deals with two tables:
users{id, name, status}
offerings{id, title, price, userid, status};
I would like that when the user table is updated an the status of a entry is change to 2 that all offerings that the user has made will be changed to i (for inactive)
CREATE OR REPLACE TRIGGER update_offering_status
BEFORE UPDATE ON users
WHEN (new.status = 2)
FOR EACH ROW
DECLARE
Userid INTEGER;
BEGIN
USERID := :old.userid;
UPDATE offering
SET status = 'i'
WHERE userid = old.userid;
END;
I am getting the error ORA-04077: WHEN clause cannot be used with table level triggers. But I am not sure how to do it without a when clause?
That's happening because your WHEN clause is in the wrong place. Put it after the FOR EACH ROW and you should be all set:
CREATE OR REPLACE TRIGGER update_offering_status
BEFORE UPDATE ON users
FOR EACH ROW
WHEN (new.status = 2)
You should be able to put it into IF & END IF instead of WHEN

Oracle Trigger for adding Old Val and New Val to audit table?

I am wanting to created an Oracle Trigger that will execute on Update on the table "User"
User
ID
Department
Privilege
Hashkey
The Oracle trigger will then add rows to the following table "Audit"
Audit
User ID
Field Name
Old_Val
New_Val
Date
Where it will record the changes of a specific field's Old value and New value and when it was changed.
My questions are:
How does it know which Field is being updated to then create a row in the Audit table to record the Old and New value of that changed field
How can I get my trigger to work when more than one field is being updated in the Update Transaction?
Is an Oracle trigger going to work for this?
Here is my code so far (it is not functional as I do not know what to put as the argument for field)
Code
CREATE OR REPLACE TRIGGER USER_UPDATE_TRG
BEFORE UPDATE OF USER_ID,Department, Privilege, Hashkey
ON USER
BEGIN
INSERT INTO AUDIT
(
USER_ID,
FIELD_NAME,
OLD_VAL,
NEW_VAL,
CHANGED_DATE
)
VALUES
(
USER_ID,
<what do I put here for Field Name?,
:old.Field,
:new.Field,
sysdate
)
END;
You can use UPDATING conditional predicate to identify the fieldname.
CREATE OR REPLACE TRIGGER USER_UPDATE_TRG
BEFORE UPDATE OF USER_ID,Department, Privilege, Hashkey
ON USER
FOR EACH ROW
BEGIN
IF UPDATING ('USER_ID') THEN
INSERT INTO AUDIT
(
USER_ID,
FIELD_NAME,
OLD_VAL,
NEW_VAL,
CHANGED_DATE
)
VALUES
(
:new.USER_ID,
'USER_ID',
:old.USER_ID,
:new.USER_ID,
SYSDATE
);
END IF;
IF UPDATING ('DEPARTMENT') THEN
.....
END IF;
IF UPDATING ('PRIVILEGE') THEN
.....
END IF;
IF UPDATING ('HASHKEY') THEN
.....
END IF;
END;
In this case if multiple columns are updated, the trigger will insert multiple records in table audit.
Edited:
the trigger you have written is statement level trigger.
the :NEW AND :OLD qualifiers will work in row level trigger for that you have to mention FOR EACH ROW.
I have added that in my code.

Create a trigger that updates a column on one table when a column in another table is updated

i have two tables
Order(id, date, note)
and
Delivery(Id, Note, Date)
I want to create a trigger that updates the date in Delivery when the date is updated in Order.
I was thinking to do something like
CREATE OR REPLACE TRIGGER your_trigger_name
BEFORE UPDATE
ON Order
DECLARE
BEGIN
UPDATE Delivery set date = ??? where id = ???
END;
How do I get the date and row id?
thanks
How do i get the date and row id?
Assuming these are columns on your ORDER table called DELIVERY_DATE and ID your trigger should look something like this:
CREATE OR REPLACE TRIGGER your_trigger_name
BEFORE UPDATE ON Order
FOR EACH ROW
BEGIN
if :new.delivery_date != :old.delivery_date
then
UPDATE Delivery d
set d.delivery_date = :new.delivery_date
where d.order_id = :new.id;
end if;
END;
Note the FOR EACH ROW clause: that is necessary to reference values from individual rows. I have used an IF construct to test whether to execute the UPDATE on Delivery. If you have no other logic in your trigger you could write it like this...
CREATE OR REPLACE TRIGGER your_trigger_name
BEFORE UPDATE OF delivery_date ON Order
FOR EACH ROW
BEGIN
UPDATE Delivery d
set d.delivery_date = :new.delivery_date
where d.order_id = :new.id;
END;
I have answered the question you asked but, as an aside, I will point out that your data model is sub-optimal. A properly normalized design would hold DELIVERY_DATE on only one table: DELIVERY seems teh logical place for it.
Use the OLD and NEW bind variables. OLD references the row or column being updated before the change is made; NEW references it after the change.
CREATE OR REPLACE TRIGGER trig1
BEFORE UPDATE
ON order REFERENCING NEW AS new
FOR EACH ROW
BEGIN
UPDATE delivery
SET ddate = :new.ddate
WHERE id = :new.id;
END;
You can modify the REFERENCING clause to give your bind variables different names. You can include OLD as <name> too. Example:
CREATE OR REPLACE TRIGGER trig1
BEFORE UPDATE
ON order REFERENCING OLD AS old_values NEW AS new_values
...
If you don't want to change the default names of "old" and "new", you can leave out the REFERENCING clause completely.
There is an implicit new and old reference in the trigger in the form of:
REFERENCING OLD AS OLD NEW AS NEW
You can write to the :NEW value but not to the :OLD value.
UPDATE Delivery set date = :new.delivery_date where id = :new.id;
CREATE OR REPLACE TRIGGER "BUR_TABLENAME" BEFORE
UPDATE ON "TABLE" FOR EACH ROW
BEGIN
If :new.active_date is not null Then
:new.active_date := TRUNC(:new.active_date);
End If;
END;
Template:
CREATE OR REPLACE TRIGGER TRIGGER_NAME
BEFORE
UPDATE
ON TABLE_NAME
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
V_VARIABLE NUMBER (1);
BEGIN
//Do Stuff;
null;
end;
Whenever there is a need for this kind of trigger, have a good look at your design. Is there really a need for a separate delivery record? Does an order really have more than 1 delivery ?
Triggers seem nice but they do tend to mess things up pretty quickly.