Updating a view in oracle - oracle

Below, I have defined some tables, for the relevant ones I have typed in the definitions. Pretty simple, though now I'm trying to raise the salaries for those two employees in the view, and I can't complete the update having that error message you will see below. Anyone could guide me a bit, please??
Definitions for tables employees, projects and employees_projects:
create table employee
(
id number,
name varchar2(20),
mobile varchar2(10),
address varchar2(30),
salary number(6,2),
hire_date date,
department_id number
);
create table project
(
id number,
name varchar2(20),
budget number(10,2),
start_date date,
finish_date date
);
create table employee_projects
(
id number,
employee_id number,
project_id number
);
View definition is:
create view lucky_employees as
select e.name,e.salary from employees e, project p, employee_projects ep
where e.project_id=p.id and e.id=ep.employee_id and p.budget > 1000000.00 ;
SQL> select * from lucky_employees;
ID NAME SALARY
1 Maria 1365.28
2 Sonja 1365.28
Then, I try to update the view by 10%, which is something I know it's possible to do under certain conditions:
SQL>
update lucky_employees set salary = salary * 1.1;
update lucky_employees set salary = salary * 1.1
*
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table
How would it be to succesfully update it??
Thanks very much, sorry for the inconveniences!!

create view lucky_employees as
select e.name from employees e, project p, employee_projects ep
where e.project_id=p.id and e.id=ep.employee_id and p.budget > 1000000.00 ;
This error is occurring because each salary of your view doesnot uniquely map to a salary of your employees table.
More information from oracle docs is here.
Anoter explanation from Burleson here.

Related

oracle sql developer after creating table , column name came as column1,column2 .... columnN

i am using sql developer Version 21.2.1.204 and when i create table by using new table function in IDE , and entered name and select type for each field
after clicking on ok button table is created but fields name are different,
COLUMN2,
COLUMN3,
COLUMN4,
came
i entered column name properly but still this is happening
you can see in images
If the wizard is not working for you, you can write out the DDL statement in a worksheet:
CREATE TABLE table1 (
id VARCHAR2(20),
name VARCHAR2(20),
address VARCHAR2(20),
age VARCHAR2(20) -- Why not use a number?
);
And run it.
As an aside, you probably should use date_of_birth and then calculate the age rather than using an age column that will go out of date as soon as the next person reaches their birthday.
CREATE TABLE table1 (
id VARCHAR2(20),
name VARCHAR2(20),
address VARCHAR2(20),
date_of_birth DATE
);

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;

Can you use Object Types in Procedures in Oracle PL/SQL?

Hello fellow programmers. Im currently working on a webshop database for my studying program. Currently im trying to make a procedure which creates an order in the orders table for a customer when he/she/it is beeing created. I am also thinking of putting this into a constructor but since i want to use this functionality twice once when the order reaches a certain status and after creation i want to bundle this functionality in a procedure. I have spend nearly 8 hours of research and testing on this but since the feedback from oracle db on my code is 0 to nothing i cant figure out what is wrong. When i create the procedure it is not flagged as valid and i cant even see the parameters in the parameters tab when i click on the procedure. I hope the code formatting works this is my first post..
This are the types order and Customer which hold a REF to each other
CREATE TYPE ORDER_TYPE AS OBJECT(
Order_Id NUMBER,
Date_of_Creation DATE,
Items ITEM_LIST,
Status REF STATUS_TYPE,
Customer REF CUSTOMER_TYPE
);
CREATE TYPE CUSTOMER_TYPE AS OBJECT(
Customer_Id NUMBER,
Email VARCHAR2(254),
User_Name VARCHAR2(50),
Password VARCHAR2(20),
First_Name VARCHAR2(50),
Last_Name VARCHAR2(50),
Address ADDRESS_TYPE,
Shopping_Cart REF ORDER_TYPE
);
CREATE TABLE Orders OF ORDER_TYPE(Status SCOPE IS Order_Status NOT NULL, Customer NOT NULL)
NESTED TABLE Items STORE AS ORDER_ITEMS_NT_TAB;
ALTER TABLE Orders ADD CONSTRAINT PK_Orders PRIMARY KEY(Order_Id);
CREATE TABLE Customers OF CUSTOMER_TYPE(Customer_Id PRIMARY KEY,
Email NOT NULL,
User_Name NOT NULL,
Password NOT NULL,
First_Name NOT NULL,
Last_Name NOT NULL,
Address NOT NULL);
This is the procedure code. The input should be the customer created or updated. Then i want to insert a new order, i still have to change the id field to guid or uuid so every order will be unique but for testing purpose i just used 1. The item list should be empty at first and the status of the order should be status 1 which stands for "Shopping_Cart" this means that the order is still beeing created and should be displayed as shopping cart in the browser later on. After the insert i want to return the inserted row with the returning into statement so i cant update the customer and set the ref of his shopping cart to the new inserted order. I cant figure out whats wrong im still working on it but i would be greatful for any help.
CREATE PROCEDURE create_customer_order(customer IN CUSTOMER_TYPE) AS
DECLARE
shopping_c NUMBER;
BEGIN
INSERT INTO ORDERS
VALUES(1,CURRENT_DATE ,NEW ITEM_LIST(),(SELECT REF(os) FROM ORDER_STATUS os WHERE VALUE(os).STATUS_ID = 1),REF(customer))
RETURNING Order_Id INTO shopping_c;
UPDATE CUSTOMERS c
SET c.SHOPPING_CART = (SELECT REF(o) FROM ORDERS o WHERE o.ORDER_ID = shopping_c)
WHERE c.CUSTOMER_ID = customer.CUSTOMER_ID;
END;
Feel free to ask questions if something is not clear. Cheers!
I will include a working example.
But first, you did not provide all types. So i assumed them.
I see you have types that refer to eachother. This is basically not a good idea.
For storing data, you could use object types, but you could also use normal data types like number/varchar2. You would need tables orders/order_items/customers. If you want to make changes to the customer_type and your table is already populated with data, changing the type is difficult (what to do with the old data?).
But to come back at your question, here is a working example.
drop type customer_type force;
drop type order_type force;
drop type address_Type force;
drop type status_type force;
drop type item_list force;
create type STATUS_TYPE as object (
status number
);
create type ADDRESS_TYPE as object (
street varchar2(100)
);
create type ITEM_LIST as object (
itemname varchar2(100)
);
CREATE TYPE ORDER_TYPE AS OBJECT(
Order_Id NUMBER,
Date_of_Creation DATE,
Items ITEM_LIST,
Status REF STATUS_TYPE,
Customer REF CUSTOMER_TYPE
);
CREATE TYPE CUSTOMER_TYPE AS OBJECT(
Customer_Id NUMBER,
Email VARCHAR2(254),
User_Name VARCHAR2(50),
Password VARCHAR2(20),
First_Name VARCHAR2(50),
Last_Name VARCHAR2(50),
Address ADDRESS_TYPE,
Shopping_Cart REF ORDER_TYPE
);
alter type order_type compile;
drop table orders;
CREATE TABLE Orders (id number, Status status_type , Customer CUSTOMER_TYPE);
CREATE OR REPLACE PROCEDURE create_customer_order(p_customer IN CUSTOMER_TYPE) AS
shopping_c NUMBER;
BEGIN
dbms_output.enable(null);
INSERT INTO ORDERS (id, status, customer)
VALUES (1, null, p_customer)
RETURNING id INTO shopping_c;
commit;
dbms_output.put_line('id='||shopping_c);
END;
/
--Test
declare
l_customer customer_type;
begin
l_customer := customer_type (Customer_Id => 1
, email=>'a#b.org'
, user_name=>'test'
, password=>'DoyouReallyWantThis'
, first_name=>'first'
, last_name =>'last'
, address=>null --for simplicity
, shopping_cart=>null --for simplicity
);
create_customer_order(p_customer => l_customer);
end;
/
thanks for your answer.. It did not work for me and you also missed the update part in the procedure but still thank you for the effort. i managed to get the procedure working by running every code piece step by step and watching if it fails. Feels like javascript to me lol. I discovered for some reason i cant explain that you cant declare variables under the declare statement and you cant use defined object types as parameters. i could not find anything about it in the documentation. to everyone still interested how i solved the problem this is the code.
CREATE OR REPLACE PROCEDURE create_customer_order(p_customer_id IN NUMBER)
AS
BEGIN
INSERT INTO ORDERS
VALUES(1, CURRENT_DATE, NEW ITEM_LIST(),(SELECT REF(os) FROM ORDER_STATUS os WHERE os.STATUS_ID = 1),(SELECT REF(c) FROM CUSTOMERS c WHERE c.CUSTOMER_ID = p_customer_id));
UPDATE CUSTOMERS c
SET c.SHOPPING_CART = (SELECT REF(o) FROM ORDERS o WHERE DEREF(o.Customer).Customer_Id = p_customer_id AND DEREF(o.STATUS).Status_Id = 1 )
WHERE c.CUSTOMER_ID = p_customer_id;
END;

How should I use an object type in an insert DML statement?

I have created two TYPE objects to try out OOP processing in PL/SQL.
I tried to use my type o_customers in my INSERT statement, but I could not do it.
There is a Customers table. It has same columns as o_customers.
create or replace type o_customers as object (
id number,
name varchar2(40),
age number,
address o_addressC,
salary number
);
create or replace type o_addressC as object (
mahalle varchar(30),
apartman varchar(15),
ilce varchar(15),
apt_no number
);
declare
adres o_addressC;
musteri o_customers;
begin
adres := o_addressC('selami ali mah','çınar apt',' üsküdar',19);
musteri:= o_customers(10,'UĞUR SİNAN SAĞIROĞLU',26,adres,1000);
insert into customers values (musteri);
end;
" There is a customers table. it has same columns with o_customers"
In OOP it is not enough for objects to have the same structure to be compatible in a programming context: they must be the same type, or related to each other through inheritance.
So you need to create the table using that type:
SQL> create table customers of o_customers
2 /
Table created.
SQL> desc customers
Name Null? Type
---------------------- -------- -------------
ID NUMBER
NAME VARCHAR2(40)
AGE NUMBER
ADDRESS O_ADDRESSC
SALARY NUMBER
SQL>
Now your insert statement will work:
SQL> declare
2 adres o_addressC;
3 musteri o_customers;
4 begin
5 adres := o_addressC('selami ali mah','cınar apt','uskudar',19);
6 musteri:= o_customers(10,'UĞUR SİNAN SAĞIROĞLU',26,adres,1000);
7 insert into customers values(musteri);
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select * from customers;
ID NAME AGE
---------- ---------------------------------------- ----------
ADDRESS(MAHALLE, APARTMAN, ILCE, APT_NO)
------------------------------------------------------------------------------------------------------------------------------------------------------
SALARY
----------
10 UĞUR SİNAN SAĞIROĞLU 26
O_ADDRESSC('selami ali mah', 'c??nar apt', ' uskudar', 19)
1000
SQL>
Incidentally I had to make minor changes to the inserted values because the posted statement hurled
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
This is because your o_addressC type attributes are too small for strings with multi-byte characters.
Unless customers is an object table (create table customers of o_customers), you'll need to refer to the object's properties explicitly:
insert into customers
( id, name, age, address, salary)
values
( musteri.id, musteri.name, musteri.age, musteri.address, musteri.salary );
By the way, o_customer (no 's') would make more sense than o_customers for an object name.

Where does oracle store my object instances?

I've created the following two object types :
create or replace type person_typ as object (
person# varchar(10)
) not final;
create or replace type salesperson_typ under person_typ (
salesperson# varchar(10),
sSurname varchar(10),
sForename varchar(10),
dateOfBirth date
);
create table person_tab of person_typ (
person# primary key
);
And I've inserted a row using :
insert into person_tab
values (salesperson_typ('p1','s1', 'Jones', 'John', sysdate));
Which I can retrieve using the following :
select
treat(value(s) as salesperson_typ).person# as person_number,
treat(value(s) as salesperson_typ).sSurname as sSurname
from
person_tab s
;
However, if I look at person_tab I only see the following :
SQL> select * from person_tab;
PERSON#
----------
p1
I'm curious, where does the salesperson specific data get stored? I was almost expecting to find a salesperson table, but I can't find anything obvious.
Your object is stored invisibly in the same table.
You can check columns by querying USER_TAB_COLS:
SELECT *
FROM user_tab_cols
WHERE table_name = 'PERSON_TAB';
Then you can then use the column names* you just discovered in a query (except SYS_NC_ROWINFO$, that throws an error for me).
SELECT SYS_NC_OID$
,SYS_NC_TYPEID$
--,SYS_NC_ROWINFO$
,PERSON#
,SYS_NC00005$
,SYS_NC00006$
,SYS_NC00007$
,SYS_NC00008$
FROM PERSON_TAB;
Note*
You should not use these column names in any application because they are internal and subject to change in future patches/releases.

Resources