How do I create the update statement that checks if a vlue is lower than the reorder_point attribute for a product - oracle

Utilize the Outdoor Clubs & Product database to create a trigger “product_reorder_au” that is associated with an update operation on the product table. The trigger checks to see whether during the update of the quantity_in_stock attribute, if its value gets lower than the reorder_point attribute value for a product. When this situation occurs, the trigger automatically inserts a new purchase order in the purchase_order table. The new purchase order will use the existing supplier_no attribute value for the product in the product table, and the quantity attribute value will be same as the reorder_qty value for the product in the product table. Save the trigger source as a script file.
This is what the product table looks like
So far this is what I have but I am just generally confused on how to update the table and add in what I am guessing would be an if then statement to only update when the reorderpoint is lower than the quantitiy_in_stock.
CREATE TRIGGER product_reorder_au
AFTER UPDATE OF product
for each row
begin
IF Quantity_In_Stock < Reorder_Point
THEN
INSERT INTO Purchase_Order (Po_No, Po_Date, Product_Id, Quantity, Supplier_id)
VALUES ( );
END IF;
END;
--Test Script
update product
set quantity_in_stock = 5
where product_id = 10012;
Attached in the other tables

You need a BEFORE trigger not AFTER trigger. See below:
--Table Preparation
CREATE TABLE product_1 (
quantity_in_stock NUMBER,
reorder_point NUMBER,
product_id NUMBER,
supplier_id NUMBER,
reorder_qty NUMBER
);
INSERT INTO product_1 VALUES (
20,
5,
10010,
500,
25
)
CREATE TABLE purchase_order (
po_no NUMBER,
po_date DATE,
product_id NUMBER,
quantity NUMBER,
supplier_id NUMBER
);
SQL> Select * from product_1;
QYT_IN_STOCK REORDER_PNT PRDT_ID SUPP_ID RERDR_QTY
----------- ---- ----- ----- -----
4 5 10010 500 25
--Trigger
CREATE TRIGGER product_reorder_au BEFORE
UPDATE ON product_1
FOR EACH ROW
WHEN ( new.quantity_in_stock < old.reorder_point )
BEGIN
INSERT INTO purchase_order (
po_no,
po_date,
product_id,
quantity,
supplier_id
) VALUES (
1, --Populate this coulmn by a sequence or by some logic
SYSDATE,
:old.product_id,
:old.reorder_qty,
:old.supplier_id
);
END;
Execution:
SQL> UPDATE product_1
SET
quantity_in_stock = 4
WHERE product_id = 10010;
SQL> SELECT * FROM purchase_order;
PO_NO PO_DATE PRODUCT_ID QTY SUPP_ID
----- ------- -------- ---- -------
1 25-10-18 10010 25 500

Related

Oracle PL/SQL Procedure with for loop to insert/update

I need to write PL/SQL procedure with cursor for loop to insert/update the data rowwise.
Data from staging table needs to be populated to main table.
It will first check if the project_id and department exist or not in main table,then it will insert/update accordingly.
(Merge cannot be used as per requirement)
So i have staging table which gets populated.
STAGE_PROJECT
So, if the project_id,department exist,contract and scope columns would get updated.
Else the row would get inserted.
Destination table:
PROJECT_DATA
Example: for ERP and SAP, contract and scope would get updated and for DWH,since the project_id and department do not exists, row will get inserted .
Hopes this helps
I created your tables.
CREATE TABLE STAGE_PROJECT
(
PROJECT_ID NUMBER,
DEPARTMENT VARCHAR2(30),
CONTRACT VARCHAR2(30),
"SCOPE" VARCHAR2(30),
FINAL_DATE DATE
);
CREATE TABLE PROJECT_DATA
(
PROJECT_ID NUMBER,
DEPARTMENT VARCHAR2(30),
CONTRACT VARCHAR2(30),
"SCOPE" VARCHAR2(30),
FINAL_DATE DATE
);
And inserted your data.
INSERT INTO PROJECT_DATA(PROJECT_ID, DEPARTMENT) VALUES (1 , 'ERP');
INSERT INTO PROJECT_DATA(PROJECT_ID, DEPARTMENT) VALUES (2 , 'SAP');
INSERT INTO STAGE_PROJECT(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE) VALUES (1 , 'ERP', 'NEW','FINAL');
INSERT INTO STAGE_PROJECT(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE) VALUES (2 , 'SAP', 'OLD','UPCOMING');
INSERT INTO STAGE_PROJECT(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE) VALUES (3 , 'DWH', 'NEW CONTRA','TARGET');
SELECT * FROM PROJECT_DATA;
SELECT * FROM STAGE_PROJECT;
This PLSQL code loop through your STAGE_PROJECT rows
If rows found in the PROJECT_DATA it will update those rows
otherwise, it will insert the row which is not found.
DECLARE
CURSOR SPCUR IS SELECT * FROM STAGE_PROJECT;
EX PLS_INTEGER;
BEGIN
FOR STAGE_PROJECT_REC IN SPCUR
LOOP
SELECT COUNT(*) INTO EX FROM PROJECT_DATA WHERE
PROJECT_ID = STAGE_PROJECT_REC.PROJECT_ID AND
DEPARTMENT = STAGE_PROJECT_REC.DEPARTMENT;
IF EX > 0 THEN
UPDATE PROJECT_DATA SET CONTRACT = STAGE_PROJECT_REC.CONTRACT,
SCOPE = STAGE_PROJECT_REC.SCOPE,
FINAL_DATE = STAGE_PROJECT_REC.FINAL_DATE
WHERE PROJECT_ID = STAGE_PROJECT_REC.PROJECT_ID AND
DEPARTMENT = STAGE_PROJECT_REC.DEPARTMENT;
ELSE
INSERT INTO PROJECT_DATA(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE, FINAL_DATE)
VALUES (STAGE_PROJECT_REC.PROJECT_ID, STAGE_PROJECT_REC.DEPARTMENT, STAGE_PROJECT_REC.CONTRACT, STAGE_PROJECT_REC.SCOPE, STAGE_PROJECT_REC.FINAL_DATE);
END IF;
END LOOP;
COMMIT;
END;

ORACLE avg,max,min salary TRIGGER

so i'm trying to create a trigger, but always have an error that says
Trigger LOG_SALARY compiled
LINE/COL ERROR
--------- ------------------------------------------------------------- 2/2 PL/SQL: SQL Statement ignored 3/9 PL/SQL: ORA-00934: group
function is not allowed here Errors: check compiler log
Error(2,2):PL/SQL: SQL Statement ignored
Error(3,9):PL/SQL:ORA-00934:group function is not allowed here
this is my code
'''alter table department add AVG_SALARY number(10);
alter table department add MAX_SALARY number(10);
alter table department add MIN_SALARY number(10);
insert into department (AVG_SALARY, MAX_SALARY, MIN_SALARY) values (AVG(salary), MAX(salary) ,MIN(salary));
create or replace TRIGGER log_salary
after update of salary on employee
for each row
begin
insert into DEPARTMENT(AVG_SALARY, MAX_SALARY, MIN_SALARY)
values(AVG(SALARY),MAX(SALARY),MIN(SALARY));
end;
update department
set salary = salary + 100.0
where SSN =888665555;
select * from DEPARTMENT;'''
could you tell me what is wrong with my code?
thankyou in advance!
You are inserting new rows into the department table. I think you want to update them. The logic looks like this:
create or replace TRIGGER log_salary
after update of salary on employee
for each row
begin
update department
set (AVG_SALARY, MAX_SALARY, MIN_SALARY) =
(select AVG(SALARY), MAX(SALARY), MIN(SALARY)
from employee
where e.department_id = :new.department_id
end;
This however will probably generate a mutating table error. Addressing that is really difficult. For instance, consider this:
emp_id dept_id salary
1 1 10
2 1 10
3 1 5
If you change emp_id's salary to 20, then the max is 20. But if you change the salary to 5, then the max remains 10.
I would suggest that you just use a view to calculate the values on-the-fly.

What is the right PL/SQL for updating rows without a need to reinsert it?

I new at using PL/SQL and I want the following:
I have this table on Oracle SQLcl
create table Child (
id varchar not null,
name varchar not null,
gender varchar not null,
YearOfBirth number(4) not null,
YearsOfAge number(4) null,
CONSTRAINT Pk primary key (id)
);
And I want a PL/SQL (preferred anonymous) that update field of "YearsOfAge" by minusing 2020 from the "YearOfBirth" field. I could do that but my problem is that the table won't be updated until I insert the PL/SQL block again. So whenever I insert a new row, I have to insert my PL/SQL block again. I want to get the table updated whenever I insert/update a row, without a need to insert this block following a new row.
To be clearer, I just want to insert SL/SQL block one time after creating the table, then get the table's "YearsOfAge" updated whenever I insert/update/delete a row. So when I write "select * from Child;" I need to see the "YearsOfAge" with the new value that computed from subtracting 2020 from "YearOf Birth".
My current PL/SQL is below:
begin
IF INSERTING THEN
update Child set YearsOfAge = 2020 - YearOfBirth;
ELSIF DELETEING THEN
update Child set YearsOfAge = 2020 - YearOfBirth;
ELSE
update Child set YearsOfAge = 2020 - YearOfBirth;
END IF;
END;
/
If you really need to store the age this way, some options are virtual columns, views, and triggers.
Virtual Column
With a virtual column, Oracle will automatically perform the calculation on the fly.
SQL> create table Child
2 (
3 id number not null,
4 name varchar2(10) not null,
5 gender varchar2(10) not null,
6 YearOfBirth number(4) not null,
7 YearsOfAge number generated always as (2020 - yearOfBirth) null,
8 constraint pk_child primary key (id)
9 );
Table created.
SQL> insert into child(id, name, gender, yearOfBirth) values(1, 'A', 'female' , 1990);
1 row created.
SQL> insert into child(id, name, gender, yearOfBirth) values(2, 'B', 'male' , 2000);
1 row created.
SQL> insert into child(id, name, gender, yearOfBirth) values(3, 'C', 'non-binary', 2010);
1 row created.
SQL> select * from child;
ID NAME GENDER YEAROFBIRTH YEARSOFAGE
---------- ---------- ---------- ----------- ----------
1 A female 1990 30
2 B male 2000 20
3 C non-binary 2010 10
View
One downside of virtual columns is that they cannot use functions like SYSDATE, so the year has to be hard-coded. With a view, the expression can reference SYSDATE and will always be up-to-date:
create or replace view child_view as
select id, name, gender, yearOfBirth, extract(year from sysdate) - yearOfBirth yearsOfAge
from child;
Trigger (Warning)
You can also use a trigger to create the value when a row is inserted or updated:
create or replace trigger child_trg
before update or insert on child
for each row
begin
if updating('YEAROFBIRTH') or inserting then
:new.yearsOfAge := extract(year from sysdate) - :new.yearOfBirth;
end if;
end;
/
But in practice, triggers are a pain to maintain. Which leads to the question: why do you want to store this information in the first place?
Good database design should minimize the amount of redundant data. There are always exceptions, but you should have a good reason for those exceptions, like an especially complicated calculation that you don't want others to get wrong, you can't create a PL/SQL function because of an unusual security constraint, etc. Calculating something as trivial as the age may cause more problems than it solves.

creating a trigger that updates a table when a column in a different table is updated

For some reason I'm having a hard time fully understanding triggers. For my homework assignment I need to create a table that holds product id, total sales, and total quantity sold for each product (these columns are already in two different tables). Then I create a trigger that updates this table when the orderplaced column from a different table is updated to 1. Not exactly sure where to start. Since the table I created is empty would I do an UPDATE table as the assignment suggests or an INSERT since the columns are empty? If anyone can put me in the right direction I would really appreciate it..
CREATE TABLE bb_sales_sum (
idProduct number(2) NOT NULL,
total number(6,2),
quantity number);
CREATE OR REPLACE TRIGGER BB_SALESUM_TRG
AFTER UPDATE OF orderplaced on bb_basket
FOR EACH ROW
WHEN (NEW.orderplaced = 1)
DECLARE
lv_count Number;
BEGIN
if :new.orderplaced = 1 then
for item in
(select idproduct, (quantity * price) AS total, quantity
from bb_basketitem
where idbasket = :old.idbasket)
loop
select count(*)
into lv_count
from bb_sales_sum where idProduct = item.idproduct;
if lv_count = NULL then
INSERT INTO bb_sales_sum
VALUES (item.idproduct, item.total, item.quantity);
else
update bb_sales_sum
set quantity = item.quantity where
idProduct = item.idproduct;
end if;
end loop;
end if;
END;
/
You may use a MERGE in place of update, which will create a new row if there isn't one already for a given idproduct and updates the quantity and total for those rows which are already available.
CREATE OR REPLACE TRIGGER bb_salesum_trg
AFTER UPDATE OF orderplaced on bb_basket
FOR EACH ROW
WHEN (NEW.orderplaced = 1)
BEGIN
MERGE INTO bb_sales_sum t USING
( select :new.idproduct as idproduct ,
:new.quantity as quantity,
:new.total as total
from dual ) s
ON (s.idproduct = t.idproduct )
WHEN MATCHED THEN UPDATE
SET quantity = s.quantity,
total = s.total
WHEN NOT MATCHED THEN
INSERT (
idproduct,quantity,total)
VALUES
( :new.idproduct,:new.quantity,:new.total );
END;
/
DEMO
It goes basically like this:
You have a table that is recording an individual order. It may have a Product Id, Quantity and a Total or similar columns.
You put your trigger code on this table.
When someone inserts a new record here, you would take the quantity and or total and update the main products table. You will add the new quantity and total to the existing summarized values in the main table where the product id matches.

I am getting error in compililing the trigger in oracle

Need help on this trigger which updating a record when user perform update on particular column.
Ex. here I have created a table orders as below.
CREATE TABLE orders
( order_id number(5),
quantity number(4),
status_c varchar2(15),
delete_date date,
deleted_by_id varchar2(10));
I have inserted 2 records in it as below.
insert into orders values (1,25,'FAILED',null,null);
insert into orders values (1,50,'QUEUED',null,null);
select * from orders;
ORDER_ID QUANTITY STATUS_C DELETE_DA DELETED_BY
1 25 FAILED
1 50 QUEUED
Now we can see the values for column STATUS_C as 'FAILED' and 'QUEUED'
So I whenever new user updates this table - orders , and make the status as 'DELETED' for status_c, then I need to capture his details such person_id and sysdate, So I have written a below trigger on that table - Orders
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
If UPDATING then
if upper(:new.status_c) = 'DELETED' then
-- Find username of person performing UPDATE on the table
SELECT user INTO v_username
FROM dual;
-- Update delete_date field to current system date
:new.delete_date := sysdate;
-- Update deleted_by_id field to the username of the person performing the UPDATE
:new.deleted_by_id := v_username
end if;
end if;
END;
/
Warning: Trigger created with compilation errors.
I got error while compile.
I tried to udpate the table to see its impact,
update orders set status_c = 'DELETED' where order_id = 1;
update orders set status_c = 'DELETED' where order_id = 1
*
ERROR at line 1:
ORA-04098: trigger 'DISDBA.ORDERS_BEFORE_UPDATE' is invalid and failed re-validation
I need help what is the issue in trigger, and why it is not compiling.
When I checked the error using below query. it says.
`select * from user_errors where type = 'TRIGGER' and name` ='ORDERS_BEFORE_UPDATE';
NAME TYPE SEQUENCE LINE POSITION
------------------------------ ------------ ---------- ---------- ----------
TEXT
----------------------------------------------------------------------------------------------------
ORDERS_BEFORE_UPDATE TRIGGER 1 20 5
PLS-00103: Encountered the symbol "END" when expecting one of the following:
. ( * # % & = - + ; < / > at in mod not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like
between is null is not || is dangling
The symbol ";" was substituted for "END" to continue.
Need help on this.
Missing semi-colon on this line:
:new.deleted_by_id := v_username

Resources