I was working on my project, here I got this error while inserting some values in a row:
ERROR at line 1: ORA-04091: table SYSTEM.PRODUCTS is mutating,
trigger/function may not see it ORA-06512: at "SYSTEM.PROD_TOTAL",
line 2 ORA-04088: error during execution of trigger
'SYSTEM.PROD_TOTAL'
This is my insert statement:
insert into products
values (1, 1001, 'Medical', 20, 4, 1, 1, 1);
Products table :
create table Products
(
ProdId number primary key,
ProdNum number not null unique,
ProdType varchar2(15),
ProdPrice int,
ProdQuantity int,
ProdCustId int references Customers,
ProdOrdId int references Orders,
ProdStoreId int references Stores
);
Trigger code:
create trigger PROD_TOTAL
after insert ON Products
for each row
begin
update Payments
set ProdTotal = (select Products.ProdPrice * Products.ProdQuantity from Products);
end;
/
And finally my Payment table:
create table Payments
(
PayId int primary key,
PayDate date,
ProdTotal int,
FinalTotal int,
PayOrdId int references orders,
PayProdId int references Products,
PayCustId int references Customers
);
I don't know why I am getting this error, please help me in solving this issue...
A statement level trigger (i.e. without FOR EACH ROW clause) will update always all records in Payments table, I don't think that's needed. For an update of only related products, use this trigger:
create trigger PROD_TOTAL
after insert ON Products
for each row
begin
update Payments
set ProdTotal = :new.ProdPrice * :new.ProdQuantity
WHERE PayProdId = :new.ProdId ;
end;
Related
i'm new to SQL Sever
I'm trying to insert values into a table but keep getting the following error : The INSERT statement conflicted with the CHECK constraint "CK__Course__CourseCo__3A81B327". The conflict occurred in database "CustomerDB", table "dbo.Course", column 'CourseCode'.
create table Course (
CourseCode int check(len(CourseCode) =4 ),
Cdesc varchar(20),
TotalFeeCash money check(len(TotalFeeCash)=8),
TotalFeeInstallment money check(len(TotalFeeInstallment) =8),
MinDownPayment money check(len(MinDownPayment)= 8),
CourseType varchar(10),
Duration int check(len(Duration) = 4)
)
insert into Course(CourseCode,CDesc,TotalFeeCash,TotalFeeInstallment,MinDownPayment,CourseType,Duration)
values (1,'EACCP',55000,60000,10000,'full',36)
can we fix this without drop the constraint ? (i want to limit the input length to <=4) i've change the constraint check(len(CourseCode) =4 ) to check(len(CourseCode) <=4 ) but it still fail.
For the past few days, I am working on my SQL project 'Supermarket Billing Management System', here I am getting a lot of obstacles while creating this project. Since I am a beginner I am not able to solve my all issues, So please help me!!
Here is my doubt:
I have created a table called 'Payments' and inside it, I have even created a trigger and a procedure, Now I don't know how to insert the values in the Payments table because of trigger and procedure. And I want such a procedure that can add the total of the product's price of a single person and it will store into Final Total, I am not sure that my procedure code is right or not, but it was created successfully. So if there is any problem with my Procedure code then please let me know and please also tell me how can I insert it by giving an example
Paymnets table :
create table Paymnets
(
PayId int primary key, PayDate date,
ProdTotal int,
FinalTotal int,
PayOrdId int references orders,
PayProdId int references Products,
PayCustId int references Customers
);
Products table:
create table Products (
ProdId number primary key,
ProdNum number not null unique,
ProdName varchar2(15),
ProdPrice int,
ProdQuantity int,
ProdCustId int references Customers,
ProdOrdId int references Orders,
ProdStoreId int references Stores
);
Procedure :
create procedure FINAL_TOTAL(C IN NUMBER, T OUT NUMBER) IS BEGIN
UPDATE
Payments
SET
FinalTotal = FinalTotal + ProdTotal
WHERE
PayCustId = C;
Commit;
SELECT
FinalTotal into T
FROM
Payments
WHERE
PayCustId = C;
END;
/
Trigger:
create trigger PROD_TOTAL
AFTER INSERT ON Products
BEGIN
UPDATE Paymnets
SET ProdTotal = (SELECT Products.ProdPrice * Products.ProdQuantity FROM Products);
END;
/
insert statement:
insert into Payments values(1,'2020-10-07',1,1,1);
Well, after inserting this many values I knew that I'll get an error and so I got:
error:not enough values
Here I want to know, how can I insert the values in the Payment table and If my procedure code is wrong then what should I write? So please help me in solving these issues!!
I'm getting this error when I try to create this trigger. I tried everything but I don't know what seems to be the problem.
Here is the code:
CREATE OR REPLACE TRIGGER after_price_update
AFTER UPDATE
ON Item
FOR EACH ROW
DECLARE new_totalprice INT;
BEGIN
IF :OLD.price <> :new.price THEN
new_totalprice := :old.Quantity * :new.price;
INSERT INTO OrderRecord(OrderRecord_Id, Item_Id, Employee_Id, Reservation_Id, Order_Time, Quantity, TotalPrice)
VALUES(old.OrderRecord_Id, old.Item_Id, old.Employee_Id, old.Reservation_Id, old.Order_Time, old.Quantity, new_totalprice);
END IF;
END;
And the error is:
4/22 PLS-00049: bad bind variable 'OLD.QUANTITY'
The tables look like this:
CREATE TABLE Item (
Item_Id int PRIMARY KEY,
Menu_Id int,
Name varchar2(20),
Description varchar2(120),
Price int,
FOREIGN KEY(Menu_Id) REFERENCES Menu(Menu_Id)
);
CREATE TABLE OrderRecord (
OrderRecord_Id int PRIMARY KEY,
Item_Id int,
Employee_Id int,
Reservation_Id int,
Order_Time date,
Quantity int,
TotalPrice int,
FOREIGN KEY(Item_Id)References Item(Item_Id),
FOREIGN KEY(Employee_Id)References Employee(Employee_Id),
FOREIGN KEY(Reservation_Id)References Reservation(Reservation_Id)
);
Table OrderRecord is not the table being updated: you cannot reference an old value for this table; you need to read this value with some SELECT statement.
IF :OLD.price <> :new.price THEN
new_totalprice := <Quantity> * :new.price;
There is no column Quantity in the table ITEM on which you are applying trigger.
If I understand what you are wanting to do correctly, it looks like you want to update the calculated total price of all existing OrderRecord entries when an Item entry has a price change.
CREATE OR REPLACE TRIGGER after_price_update
AFTER UPDATE
ON Item
FOR EACH ROW
BEGIN
IF NVL(:OLD.Price, 0) <> NVL(:new.Price, 0) THEN
-- Update the child table "OrderRecord" for this item using new price
UPDATE OrderRecord SET TotalPrice = Quantity * :new.Price WHERE Item_Id = :new.Item_id;
END IF;
END;
Note that this trigger is on the parent table, Item, and references two values from the modified record: price and Item_Id, to update the child OrderRecord table.
Also note the use of NVL to watch for nulls because the comparison will not succeed if a null is on either side. Using zero for null is debatable; one could use a value that will never occur such as a negative number.
I got this 'Message' table.
CREATE TABLE message (
id INT PRIMARY KEY,
user_id INT NOT NULL REFERENCES users (id) ON DELETE CASCADE,
category_id INT NOT NULL REFERENCES category (id) ON DELETE CASCADE,
text VARCHAR2(4000),
media VARCHAR2(500),
creation_date DATE DEFAULT SYSDATE
);
CREATE SEQUENCE message_seq;
CREATE OR REPLACE TRIGGER message_bir
BEFORE INSERT ON message
FOR EACH ROW
BEGIN
SELECT message_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
After i insert something i need the last inserted id and the date.
INSERT INTO message (user_id, category_id, media)
VALUES (1, 1, 'fdsfsd')
RETURNING id INTO :last_insert_id
The above gives me the last inserted id, but like i said i also need the creation_date. I dont want to do a select query after...
Is there a way to get 2 values back after run an insert?
You can write:
RETURNING id, creation_date INTO :last_insert_id, :last_creation_date.
See http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/returninginto_clause.htm
I am trying to maintain data integrity and logging errors to an error table. I've got 3 tables with unique constraints and 1 error table:
create table tbl_one (
pass_no number,
constraint tbl_one_u01 unique (pass_no) );
insert into tbl_one values(10);
insert into tbl_one values(20);
create table tbl_two (
cus_no number,
cus_name varchar2(50),
pass_no number,
constraint tbl_two_u01 unique (cus_no) );
insert into tbl_two values( 101, 'NameX',10);
insert into tbl_two values( 102, 'NameY',10);
insert into tbl_two values( 103, 'NameZ',20);
create table tbl_target (
cus_no number,
pass_no number,
constraint tbl_target_u01 unique (cus_no),
constraint tbl_target_u02 unique (pass_no));
exec dbms_errlog.create_error_log('tbl_target','tbl_target_err');
I am trying to log all ORA-00001 errors to the error table tbl_target_err like this:
begin
insert into tbl_target
select a.pass_no, b.cus_no
from tbl_one a
inner join tbl_two b on b.pass_no = a.pass_no
log errors into tbl_target_err reject limit 10;
end;
The result is:
select * from tbl_target;
-------------------
CUS_NO PASS_NO
101 10
103 20
and the error table:
CUS_NO PASS_NO
102 10
I need all the violated errors to go into the error table. If the value of pass_no 10 is violated then all 10 values should inserted into the error table; not, one into target and one to error table. I don't want to use exists statements because I won't able to log all violated values.
How could I go about doing this?
You can't use the error logging mechanism for this as it isn't designed to support it. It errors at the point it tries to create the duplicate in the table - the first value it tries to insert for pass_no 10 is valid on its own - so it would have to distinguish between data that already existed and multiple values coming from the insert, to start with. So you'd need to roll your own.
One option is to create your own table to hold the duplicates, and use an insert all to decide which values belong in each table:
create table tbl_target_dup (
cus_no number,
pass_no number
);
insert all
when cus_count = 1 and pass_count = 1 then
into tbl_target values (cus_no, pass_no)
else
into tbl_target_dup values (cus_no, pass_no)
select a.pass_no, b.cus_no,
count(*) over (partition by a.pass_no) as pass_count,
count(*) over (partition by b.cus_no) as cus_count
from tbl_one a
join tbl_two b on b.pass_no = a.pass_no;
This allows you to have more columns than those affected by the PK/UK, and insert them only into the real table if you prefer, or a subset into the 'error' table. With just those two columns in each table you get:
select * from tbl_target;
CUS_NO PASS_NO
---------- ----------
103 20
select * from tbl_target_dup;
CUS_NO PASS_NO
---------- ----------
101 10
102 10
SQL Fiddle demo.
You could do the same thing with two inserts based on the same select, one with a subquery checking that both counts are 1, other checking that at least one is not, but this might perform better.