Update Trigger PL/SQL in Oracle [duplicate] - sql

I create the following tables:
create table products
(
code varchar(9),
group_code varchar(9),
price number,
CONSTRAINT pk_code PRIMARY KEY (code)
);
I created a trigger , for that the price per group of products does not exceed 100 dollars:
create or replace trigger nomore100
before insert or update on products
for each row
declare
cursor c_total is
select group_code, sum(price) as total_price
from products
where group_code=:new.group_code
group by group_code;
v_total c_total%rowtype;
begin
for v_total in c_total loop
if v_total.total_price+:new.price > 100 then
raise_application_error(-20150,'No more than 100 dollars');
end if;
end loop;
end nomore100;
/
The trigger works for inserts, but when i try to do a update:
update products set price=120 where code='PX1';
Oracle return:
"table %s.%s is mutating, trigger/function may not see it"
Thanks for any suggestions or answers, have a nice day!

Related

ORA-04091 tableT is mutating, trigger/function may not see it

create or replace trigger discount
after insert or update
on product
for each row
declare
newcost number;
quant number;
id number;
BEGIN
id:= :NEW.pid;
quant:= (30/100)*:NEW.req_quant;
newcost:= :NEW.pcost - (10/100)*:NEW.pcost;
if :NEW.act_quant>quant then
update product set pcost=newcost where pid=id;
end if;
dbms_output.put_line('success');
end;
while writing query insert into product values(107,20,20,1000);
i get an this error ORA-04091 tableT is mutating, trigger/function may not see it
my table is
CREATE TABLE "PRODUCT"
( "PID" NUMBER(5,0),
"ACT_QUANT" NUMBER(5,0),
"REQ_QUANT" NUMBER(5,0),
"PCOST" NUMBER(10,0),
PRIMARY KEY ("PID") ENABLE
)
After inserting or updating trigger must check that whether the actualquantity of product is greater than 30% of requaired quantity if it is true we need to give discount of 10% on that product
Don't literally update table which is just being modified (which caused trigger to fire) because trigger can't see it; that's the good, old mutating table error.
if :NEW.act_quant > quant then
:new.pcost := newcost; --> use this
-- update product set pcost=newcost where pid=id; --> not this
end if;
Though, the whole trigger can be shortened to
create or replace trigger discount
after insert or update on product
for each row
begin
:new.pcost := case when :new.act_quant > (30/100) * :new.req_quant then 0.9 * :new.pcost
else :new.pcost
end;
end;

Trigger to allow 1 car per customer and not let another customer rent an already rented vehicle between rental and return date [duplicate]

This question already has answers here:
How to enforce key uniqueness in a temporal table?
(3 answers)
Closed 11 months ago.
I have a project based on Databases (Oracle) to create a Rental shop for cars. So far it's been going well but I got stuck on a trigger that has to check the customer as well as the car between the rental as well as the return date, so that a customer who's already rented a vehicle cannot rent another and another customer cannot rent an already rented vehicle.
Rental Table:
CREATE TABLE RentAuto
(
auto_id INT,
customer_id INT,
employee_id INT,
date_rent DATE,
date_return DATE,
rent_days VARCHAR2(5)
);
Automobile Table:
CREATE TABLE Automobile
(
auto_id INTEGER NOT NULL,
year_of_production VARCHAR(10),
auto_current_km VARCHAR(20),
price_per_day VARCHAR(20),
color_id INT,
is_auto_av INT,
model_id INT,
PRIMARY KEY(auto_id)
);
Insert into the Table:
INSERT INTO RentAuto (auto_id,customer_id,employee_id,date_rent,date_return, rent_days)
VALUES(14,13,3,TO_DATE(sysdate, 'dd-mm-yyyy'), '29-03-2022','2');
The trigger I wrote below gives me an error on the IF statement and I can't figure out how to fix it.
(PLS-00201:identifier 'NEW.CUSTOMER_ID' must be declared)
create or replace TRIGGER RENTINGTRIGGER
BEFORE INSERT OR UPDATE OF AUTO_ID,CUSTOMER_ID,DATE_RENT,DATE_RETURN ON RENTAUTO
FOR EACH ROW
BEGIN
IF RENTAUTO.CUSTOMER_ID = :NEW.CUSTOMER_ID
and ((new.DATE_RENT >= RentAuto.DATE_RETURN and new.DATE_RENT < RentAuto.DATE_RETURN)
or (new.DATE_RETURN > RentAuto.DATE_RENT and new.DATE_RETURN < RentAuto.DATE_RETURN))
THEN
RAISE_APPLICATION_ERROR(-2099, 'You can only book one car per single customer a day');
IF RentAuto.AUTO_ID = :NEW.AUTO_ID
and
((new.date_rent >= RentAuto.date_return and new.date_rent < RentAuto.date_return)
or (new.date_return > RentAuto.date_rent and new.date_return < RentAuto.date_return))
THEN
RAISE_APPLICATION_ERROR(-2099, 'Car has already been rented by another customer!');
END IF;
END IF;
END;
Here is a simple after statement trigger, that throws an exception when an insert or update leads to a customer booking more than one car a day or a car getting booked more than once a day.
If the insert or update statement is on more than one row, the trigger doesn't tell us which booking led to failure. Also, each time an insert or update occurs we must scan the whole table for clashes. If you only want to react on the row(s) being inserted or updated, you need a compound trigger, where you remember the rows in question in the "after each row" part and then compare them to the other rows in the table in the "after statement" part.
CREATE OR REPLACE TRIGGER rentingtrigger
AFTER INSERT OR UPDATE OF auto_id, customer_id, date_rent, date_return ON rentauto
v_count INTEGER;
BEGIN
select count(*)
into v_count
from rentauto
where exists
(
select null
from rentauto other
where other.customer_id = rentauto.customer_id
and other.date_rent <= rentauto.date_return
and other.date_return >= rentauto.date_rent
and other.rowid <> rentauto.rowid
);
IF v_count > 0 THEN
RAISE_APPLICATION_ERROR(-20099, 'You can only book one car per single customer a day');
END IF;
select count(*)
into v_count
from rentauto
where exists
(
select null
from rentauto other
where other.auto_id = rentauto.auto_id
and other.date_rent <= rentauto.date_return
and other.date_return >= rentauto.date_rent
and other.rowid <> rentauto.rowid
);
IF v_count > 0 THEN
RAISE_APPLICATION_ERROR(-20099, 'Car has already been rented by another customer!');
END IF;
END rentingtrigger;

Mutating trigger in Oracle

I create the following tables:
create table lessons(
id number,
name_teacher varchar2(9),
name_student varchar2(40),
start_lesson date,
end_lesson date
);
I inserted the following datas:
insert into lessons values (001,'Peter','Thomas',to_date('2015-12-15','YYYY-MM-DD'),to_date('2015-12-22','YYYY-MM-DD'));
insert into lessons values (002,'Eli','Alice',to_date('2015-06-16','YYYY-MM-DD'),to_date('2015-06-23','YYYY-MM-DD'));
insert into lessons values (003,'Daniel','Thomas',to_date('2015-08-15','YYYY-MM-DD'),to_date('2015-08-20','YYYY-MM-DD'));
Data that you cant add by the trigger.
insert into lessons values (001,'Peter','Alice',to_date('2015-12-16','YYYY-MM-DD'),to_date('2015-12-25','YYYY-MM-DD'));
insert into lessons values (002,'Eli','Thomas',to_date('2015-06-13','YYYY-MM-DD'),to_date('2015-06-20','YYYY-MM-DD'));
The question is how to make a trigger that does not allow me to add students who have teachers who overlap in time, like "Peter" or "Eli".
--- My problem ---
Oracle returns me an error of mutants tables.
you neen an after insert / update Trigger that fire after the comlete insert or update and not after earch row:
create or replace trigger check_intersections_trg
on
lessons
after insert or update
declare
v_res NUMBER;
begin
select count(*)
into v_res
from lessons l1
join lessons l2 on l1.name_student = l2.name_student
and l1.start_lesson <= l2.end_lesson
and l2.start_lesson <= l1.end_lesson
;
if v_res > 0 than
raise_application_error( -20999, 'intersection found');
end if;
end;
/

"Table is mutating" error occurs when inserting into a table that has an after insert trigger

I'm trying to create an after insert trigger that inserts the details of a purchase made into a purchases log table and, as well, update the total cost column in the purchases table to add GCT of 16.5% to the total. The two tables have these columns:
CREATE TABLE purchases
(
p_Id INTEGER PRIMARY KEY,
product VARCHAR(25) ,
quantity INTEGER ,
unit_Cost FLOAT ,
total_Cost FLOAT
);
CREATE TABLE purchases_log
(
event_Date DATE ,
p_Id INTEGER PRIMARY KEY,
description varchar(75)
);
The trigger I'm trying to use is:
CREATE OR REPLACE TRIGGER PURCHASES_AUDIT
AFTER INSERT ON purchases
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE TAX FLOAT;
BEGIN
INSERT INTO purchases_log
VALUES(SYSDATE,:NEW.p_Id,'INSERT INTO PURCHASES TABLE');
tax := 1.165;
UPDATE purchases SET total_Cost = quantity * unit_Cost;
UPDATE purchases SET total_Cost = total_Cost*tax;
END PURCHASES_AUDIT;
/
however when trying to run an insert on the purchase table oracle gives me this error
ERROR at line 1:
ORA-04091: table PURCHASES is mutating, trigger/function may
not see it
ORA-06512: at "PURCHASES_AUDIT", line 9
ORA-04088: error during execution of trigger 'PURCHASES_AUDIT'
Please Help
Don't update the table on which the trigger is defined.
It sounds like you want a before insert trigger, not an after insert trigger, that modifies the :new pseudo-record. If I understand your intention correctly
CREATE OR REPLACE TRIGGER PURCHASES_AUDIT
BEFORE INSERT ON purchases
FOR EACH ROW
DECLARE
TAX FLOAT;
BEGIN
INSERT INTO purchases_log
VALUES(SYSDATE,:NEW.p_Id,'INSERT INTO PURCHASES TABLE');
tax := 1.165;
:new.total_Cost = :new.quantity * :new.unit_Cost * tax;
END PURCHASES_AUDIT;
As an aside, do you really, really want to use a float rather than a number? Do you fully understand the approximate nature of floating point numbers? I've never come across anyone working with money that wanted to use a float.
As a point of clarification: before triggers allow you to update the :new values, after triggers do not. The :new values if after triggers will always contain the final value.

ORA-00933: SQL command not properly ended? Enter Bind Variables?

I am attempting to write out in my SQL commands for Oracle Apex 5, and I cannot see why I'm getting an error. Also, a popup window appears once I submit asking to 'Enter Bind Variables' for ':NEW'? Isn't it already declared?
drop table tmpcapacityguide cascade constraints;
drop table tmpcaravanpark cascade constraints;
create table tmpcaravanpark as select * from Caravan_park;
create table tmpcapacityguide
(mincap number(3),
maxcap number(3));
insert into tmpcapacityguide values(30, 150);
CREATE OR REPLACE TRIGGER "PARK_CAPACITY_CHECK"
before insert or update of capacity
on Caravan_park
for each row
when (:new.capacity < 30) DECLARE
mincapacity integer;
maxcapacity integer;
begin
select mincap, maxcap
into mincapacity, maxcapacity
from tmpcapacityguide
where capacity = :new.capacity;
if (new.capacity < mincapacity)
then raise_application_error(-20601, 'Capacity must be between 30 and 150');
end if;
end;
:new.capacity is input and has to be declared. For more info see here: http://www.akadia.com/services/ora_bind_variables.html
Try using slashes, and name of trigger after last end, and also You do not need ":" sign before new variable in IF statement:
drop table tmpcapacityguide cascade constraints;
drop table tmpcaravanpark cascade constraints;
create table tmpcaravanpark as select * from Caravan_park;
create table tmpcapacityguide (mincap number(3), maxcap number(3));
/
insert into tmpcapacityguide values(30, 150);
/
CREATE OR REPLACE TRIGGER PARK_CAPACITY_CHECK
before insert or update of capacity on caravan_park
for each row
when (new.capacity < 30)
declare
mincapacity integer;
maxcapacity integer;
begin
select mincap, maxcap
into mincapacity, maxcapacity
from tmpcapacityguide
where capacity = :new.capacity;
if (new.capacity < mincapacity)
then
raise_application_error(-20601, 'Capacity must be between 30 and 150');
end if;
end PARK_CAPACITY_CHECK;
/
Also, You should execute it as a script, not statement in SQL Developer. This can be done by pressing F9, not F5, as sstated here.
EDIT:
As for Your ORA-00904 error, You still do not have capacity column in Your tmpcapacityguide table. And You try to use it here:
select mincap, maxcap
into mincapacity, maxcapacity
from tmpcapacityguide
where capacity = :new.capacity;