oracle triggers :new context variable - oracle

Question:
A Trigger which automatically stores in a separate table called ‘ExcellentSale’ the Sales Agent
name, car model and manufacturer name, each time the agreed price of a
SalesTransaction is more than 20% of the car’s asking price. (Note: You need to create
the ‘ExcellentSale’ table before implementing this trigger. To create the primary key, use a
sequence that starts at 1 and increments by 1).
I am using these tables
Manufacturer(manufacturerID, name, region)
Model(modelNo, name, type, previousModel, manufacturerID)
Car(VIN, dateAcquired, yearBuilt, purchasedPrice, askingPrice,
currentMileage, modelNo)
SalesAgent(agentID, name, DOB)
SalesTransaction(VIN, custID, agentID, dateOfSale, agreedPrice)
Here is my attempt
create sequence generateKey
start with 1
increment by 1;
CREATE TABLE ExcellentSale(
recordNo NUMBER,
agentName VARCHAR2(20) NOT NULL,
modelName VARCHAR2(20) NOT NULL,
manufacturerName VARCHAR2(20) NOT NULL,
PRIMARY KEY(recordNo));
create or replace trigger AutoStore
before insert on SalesTransaction
for each row
declare
SAname varchar2(50);
carModel varchar2(50);
manufacturerName varchar2(50);
askingprice number;
agreedprice number;
begin
select sa.name, mo.name, mu.name, c.askingprice, st.agreedprice
into SAname, CarModel, manufacturerName, askingprice, agreedprice
from manufacturer MU, Model MO, Car C, SalesAgent SA, SalesTransaction ST
where mu.manufacturerid = mo.manufacturerid
and st.vin = c.vin
AND c.vin = :new.vin
AND sa.agentID = :new.agentID;
IF :new.agreedPrice > (1.2 * askingPrice) THEN
INSERT INTO ExcellentSale
VALUES
(generateKey.nextval, agentName, modelName, manufacturerName);
END IF;
end AutoStore;
/
and the error I am getting is
PL/SQL: ORA -00984: Column not allowed here
please help, thank you in advanced.

In the VALUES clause of the insert statement, you have go use the variables that hold the values you need instead of the column names.
INSERT INTO ExcellentSale
VALUES
(generateKey.nextval, SAname, CarModel, manufacturerName);

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 PLS-00049: bad bind variable

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.

PLS-00049 : Eroor when using :NEW

I have two tables
A(#ref_medic,libelle, vignette,remarque, qtestock)
B(#ref_medic, #dateF, qte_lot, unite, remarque)
I want to use the instead of insert trigger in order to insert a row in B in case the row having its ref_medic is existent in A but not in B.
I keep getting the error :
PLS-00049: bad bind variable 'NEW.REF_MEDIC'
whenever I'm inserting in this view :
This is the view I'm inserting through thanks to INSTEAD OF INSERT TRIGGER
CREATE VIEW myview(reference,libelle,vignette, date_peremption, Quantite,unite,
Remarque) AS
SELECT M.ref_medic, libelle, vignette, dateF,Qte_lot,unite,LM.remarque
FROM Medicament M, Lot_medicament LM
WHERE M.ref_medic=LM.ref_medic
AND qte_lot>0;
I tried removing :NEW but that's not what i'm looking forward to do as I want to insert this row in B :
INSERT INTO myview VALUES
('12AS45','test','yes','06/06/2021',30,'boite','test');
PLS-00049: variable attachée (bind variable) erronée 'NEW.REF_MEDIC'
We should get the folllowing result: the row won't be inserted in B as it's existant there
Is there a '#' in the name of your column ? it might cause problem.
Otherwise it should be working.
Here is a tested example :
create table Medicament(
ref_medic VARCHAR2(10),
libelle VARCHAR2(30),
vignette VARCHAR2(3),
remarque VARCHAR2(50),
qtestock NUMBER);
create table Lot_medicament(
ref_medic VARCHAR2(10),
dateF DATE,
qte_lot NUMBER,
unite VARCHAR2(15),
remarque VARCHAR2(50));
CREATE VIEW myview(reference,libelle,vignette, date_peremption, Quantite,unite, Remarque) AS
SELECT M.ref_medic, libelle, vignette, dateF, Qte_lot, unite, LM.remarque
FROM Medicament M, Lot_medicament LM
WHERE M.ref_medic = LM.ref_medic
AND qte_lot > 0;
CREATE OR REPLACE TRIGGER instead_insert_in_myview
INSTEAD OF INSERT ON myview
DECLARE
med_ref Medicament.ref_medic%TYPE;
BEGIN
BEGIN
SELECT ref_medic into med_ref FROM Medicament where ref_medic = :new.reference;
EXCEPTION
WHEN NO_DATA_FOUND THEN
med_ref := NULL;
END;
IF med_ref IS NULL THEN
INSERT INTO Medicament(ref_medic, libelle, vignette, remarque, qtestock)
VALUES (:new.reference, :new.libelle, :new.vignette, :new.remarque, :new.Quantite);
END IF;
INSERT INTO Lot_medicament(ref_medic, dateF, qte_lot, unite, remarque)
VALUES (:new.reference, :new.date_peremption, :new.Quantite, :new.unite, :new.remarque);
END instead_insert_in_myview;
/
INSERT INTO myview VALUES
('12AS45','test','yes','06/06/2021',30,'boite','test');
then
select count(*) from Medicament;
gives you one row, and
select count(*) from Lot_medicament;
also gives you one row.
The mistake is writing :NEW.ref_med instead of :NEW.reference inside the trigger.
Thanks everybody .

Procedure to add history of an event to Oracle SQL

I need to write a procedure in Oracle SQL that inserts data from three tables into one separate table without any keys. Here is the model of my database:
. (All of the column names are in Polish, sorry about that).
I have already created a table for history:
create table art_historia(
data_koncertu date default sysdate, --Concert date
miejsce_koncertu varchar2(40), --Place of concert
nazwa_zespolu varchar2(30), --Name of band
liczba_widzow number(5), --Number of viewers
bilans_finansowy number (8,2)); --Finance balance
And the values that I want to insert there using this procedure I can picture with this select:
select s.miasto, a.nazwa_zespolu, k.ilosc_sprzedanych_biletow, k.zysk
from art_sala s, art_koncert k, art_artysta a
where k.kod_sali_koncertowej = s.kod_sali_koncertowej and
k.kod_artysty = a.kod_artysty and
k.id_koncertu = (variable of concert id);
How can I do this?
Try this
CREATE PROCEDURE INSERT_ART_HIST_P (p_in_concert_id number) IS
BEGIN
INSERT INTO art_historia
select s.miasto, a.nazwa_zespolu, k.ilosc_sprzedanych_biletow, k.zysk
from art_sala s, art_koncert k, art_artysta a
where k.kod_sali_koncertowej = s.kod_sali_koncertowej and
k.kod_artysty = a.kod_artysty and
k.id_koncertu = p_in_concert_id;
END;

Deleting specific record from nested table Oracle DB

I'm having problems deleting specific record from the table (ORACLE DB).
I have a table with a nested table inside of it.
Table structure looks like this: where ML - nested table
Name, City, ML(Brand, Model, ID, Year, Price)
What I need to do is delete specific record with ID of 'L201'.
What I have tried so far:
SELECT B.ID FROM TABLE Dock A, Table(A.ML) B;
This is working giving me all the ID's.
Output:
ID
____
B201
S196
L201
This is not working when trying to delete the record:
DELETE FROM Dock
(SELECT B.ID FROM Dock A, Table(A.ML) B) C
WHERE C.ID = 'L201';
Getting error:
Line 2: SQL command not properly ended;
DELETE FROM TABLE
(SELECT D.ML FROM Dock D) E
WHERE E.ID = 'L201';
Throws an error:
single-row subquery returns more than one row
Maybe this one:
DELETE FROM
(SELECT A.Name, A.City, d.Brand, d.Model, d.ID, d.Year, d.Price
FROM Dock A, TABLE(ML) d)
WHERE ID = 'L201';
Update:
Another trial before we gonna make it more advanced:
DELETE FROM Dock
WHERE ROWID =ANY (SELECT a.ROWID FROM Dock a, TABLE(ML) b WHERE b.ID = 'L201');
Update 2:
If you prefer it more object-oriented, this one should work as well. At least I did not get any error.
CREATE OR REPLACE TYPE ML_TYPE AS OBJECT (
brand VARCHAR2(100),
ID VARCHAR2(20),
MODEL VARCHAR2(20),
YEAR NUMBER,
Price NUMBER,
MAP MEMBER FUNCTION getID RETURN VARCHAR2,
CONSTRUCTOR FUNCTION ML_TYPE(ID IN VARCHAR2) RETURN SELF AS RESULT);
CREATE OR REPLACE TYPE BODY ML_TYPE IS
CONSTRUCTOR FUNCTION ML_TYPE(ID IN VARCHAR2) RETURN SELF AS RESULT IS
-- Constructor to create dummy ML-Object which contains just an ID,
-- used for comparison
BEGIN
SELF.ID := ID;
RETURN;
END ML_TYPE;
MAP MEMBER FUNCTION getID RETURN VARCHAR2 IS
BEGIN
RETURN SELF.ID;
END getID;
END;
/
CREATE OR REPLACE TYPE ML_TABLE_TYPE IS TABLE OF ML_TYPE;
CREATE TABLE Dock (Name VARCHAR2(20), City VARCHAR2(20), ML ML_TABLE_TYPE)
NESTED TABLE ML STORE AS ML_NT;
insert into Dock values ('A', 'NY', ML_TABLE_TYPE(
ML_TYPE('brand1','L301','Model 2',2013, 1000),
ML_TYPE('brand2','L101','Model 3',2013, 1000)));
insert into Dock values ('B', 'NY', ML_TABLE_TYPE(
ML_TYPE('brand3','K301','Model 4',2014, 3000),
ML_TYPE('brand4','K101','Model 5',2014, 3000)));
insert into Dock values ('A', 'NY', ML_TABLE_TYPE(
ML_TYPE('brand5','K301','Model 8',2012, 2000),
ML_TYPE('brand6','L201','Model 9',2012, 2000)));
DELETE FROM Dock WHERE ML_TYPE('L201') MEMBER OF ML;
After reading some literature I think I found the correct way to do this.
By defining a mapping-function for your object-type you can compare two nested tables directly.
Example:
-- creating the custom object type
create or replace type ml_type as object (
brand varchar2(100),
id varchar2(20),
map member function sort_key return varchar2
);
-- creating the object type body and defining the map-function
create or replace type body ml_type as
map member function sort_key return varchar2 is
begin
return self.brand || '|' || self.id;
end;
end;
/
-- creating the nested table of custom type
create or replace type ml_tab as table of ml_type;
-- deleting from your table by comparing the nested-table elements
delete from dock where ml = (select ml from dock a, table(a.ml) b where b.id = 'L201');
In this example the map-functions is just returning the concatenated version of brand and id, but you can define it to what you want/need.

Resources