what is the difference between nested table and object type in oracle? - oracle

I have following object tables in oracle DB.
create type deposit_ty as object
(
depno number(6),
depcategory ref depcategory_ty,
amount number(6),
period number(2)
);
create type deposit_ntty as table of deposit_ty;
create type address_ty as object
(
homeno number,
street varchar(30),
city varchar(30)
);
create type customer_ty as object
(
cusid char(4),
custname varchar(40),
address address_ty,
dob DATE,
deposits deposit_ntty
);
can any one tell what is the difference between column address and deposits in customer_ty object table?

An object type/abstract data type/record is like a row or tuple: it contains an ordered set of attributes. To populate address you must set one and only one value for each of homeno, street, and city.
A nested table is like a table: it contains an unordered set of rows. Usually a nested table only contains a set of simple values, like a number. In your example, it is a set of object types. To populate deposits you can create any number of deposit_ty.
For example:
declare
customer customer_ty :=
customer_ty(
'ABC',
'Name',
address_ty('123', 'fake street', 'Springfield'),
sysdate,
deposit_ntty(
deposit_ty(1, null, 100, 1),
deposit_ty(2, null, 200, 2)
)
);
begin
null;
end;
Also, you probably want to use a VARCHAR2 instead of VARCHAR or CHAR. And if it's not too late, throw out all this object stuff and use tables like everyone else.

Related

When inserting values into an object table in Oracle SQL, how do you declare nested objects?

I'm experimenting with objects and nested tables to get an understanding of how they work.
I have created three objects types - Address, Property, and Sale. Address is nested in Property, and Property is nested in Sale. I have then created a Sold table - of type Sale.
CREATE OR REPLACE TYPE ADDRESS AS OBJECT(
line_1 VARCHAR2 (10),
town VARCHAR2 (10),
postcode VARCHAR2(10)
);
CREATE OR REPLACE TYPE PROPERTY AS OBJECT(
location ADDRESS,
description VARCHAR2(10)
);
CREATE OR REPLACE TYPE SALE AS OBJECT(
house PROPERTY,
sale_price NUMBER
);
CREATE TABLE SOLD OF SALE;
However, when I try to insert values using any of the parenthesis groupings below, I get the error 'missing right parenthesis or' too many values'.
INSERT INTO SOLD VALUES ((('1 MY ROAD', 'MYTOWN', 'MY123'), 'DESCRIPTION'), 100000);
INSERT INTO SOLD VALUES (('1 MY ROAD', 'MYTOWN', 'MY123', 'DESCRIPTION'), 100000);
INSERT INTO SOLD VALUES ('1 MY ROAD', 'MYTOWN', 'MY123', 'DESCRIPTION', 100000);
In this context what is the correct way to group nested objects to avoid errors?
Use the object constructors:
INSERT INTO sold (house, sale_price)
VALUES (
property(
address('1 MY ROAD', 'MYTOWN', 'MY123'),
'DESCRIPTION'
),
100000
);
or:
INSERT INTO sold
VALUES (
sale(
property(
address('1 MY ROAD', 'MYTOWN', 'MY123'),
'DESCRIPTION'
),
100000
)
);
Note: DESCRIPTION is 11 characters so it will not fit into a VARCHAR2(10) attribute. Either increase the size of the attribute or reduce the size of the string literal you are trying to put into the attribute.
db<>fiddle here

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;

Insertion in Nested Tables on Oracle DB

I am a new learner of PL/SQL databases,A kind of exercise given to apply database on apex.oracle.com with given sequence.Then I have created tables but when it comes to fill tables with the insertion code as follows,Application has given error,Would you mind if I need your assistance
Thanks in Advance,
CREATE TYPE TEMPORAL_VARCHAR AS OBJECT (
VALID_TIME_LOWER_BOUND DATE,
VALID_TIME_UPPER_BOUND DATE,
VALUE_PART VARCHAR2(50)
);
CREATE TYPE TEMPORAL_NUMBER AS OBJECT (
VALID_TIME_LOWER_BOUND DATE,
VALID_TIME_UPPER_BOUND DATE,
VALUE_PART NUMBER );
Time-related attributeshave defined with the code as follows;
CREATE TYPE NAME_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE ADDRESS_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE DEPARTMENT_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE MANAGER_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE SALARY_TYPE AS TABLE OF TEMPORAL_NUMBER;
CREATE TABLE EMPLOYEE (
SSN NUMBER primary key,
NAME NAME_TYPE,
ADDRESS ADDRESS_TYPE ,
BIRTH_DATE DATE,
MANAGER MANAGER_TYPE ,
DEPARTMENT DEPARTMENT_TYPE,
SALARY SALARY_TYPE
)
NESTED TABLE NAME STORE AS NAME_TABLE,
NESTED TABLE ADDRESS STORE AS ADDRESS_TABLE,
NESTED TABLE MANAGER STORE AS MANAGER_TABLE,
NESTED TABLE DEPARTMENT STORE AS DEPARTMENT_TABLE,
NESTED TABLE SALARY STORE AS SALARY_TABLE
;
And the insertion that I am inteded to do
INSERT INTO EMPLOYEE VALUES
(101,
NAME(TEMPORAL_VARCHAR('23.11.2005','12.31.9999','James Brown')),
ADDRESS(TEMPORAL_VARCHAR('23.11.2005','12.31.9999','BUCA, IZMIR')),
'23.10.1986',
MANAGER(TEMPORAL_VARCHAR('23.11.2005','12.31.9999','Mike White')),
DEPARTMENT(TEMPORAL_VARCHAR('23.11.2005','12.31.9999','DEPT_ID05')),
SALARY(TEMPORAL_NUMBER('23.11.2005',’12.31.9999’, 250000))
);
And the error message I recieved is :
ORA-00904: "SALARY": invalid identifier
There are spaces before _ here
CREATE TYPE MANAGER _TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE SALARY _TYPE AS TABLE OF TEMPORAL_NUMBER;
DEPARTMENT DEPARTMENT _TYPE
A comma is missing after DEPARTMENT _TYPE
try this solution:
'alter session set NLS_DATE_FORMAT='DD.MM.YYYY';'
----------------------------------------------------
INSERT INTO EMPLOYEE VALUES
(101,
NAME_TYPE(TEMPORAL_VARCHAR('23.10.1986','09.09.9999','James Brown')),
ADDRESS_TYPE(TEMPORAL_VARCHAR('15.12.2009','09.09.9999','BUCA')),
'23.10.1986',
MANAGER_TYPE(TEMPORAL_VARCHAR('24.05.2008','09.09.9999','Mike White')),
DEPARTMENT_TYPE(TEMPORAL_VARCHAR('03.01.2012','09.09.9999','DEPT_ID05')),
SALARY_TYPE(TEMPORAL_NUMBER('01.01.2003','09.09.9999', 3200))
);

What is the purpose of "RETURN AS VALUE" in NESTED TABLES (Oracle 9i)

Is there a specific case, when i should use RETURN AS VALUE?
Normally i use only NESTED TABLE xxx STORE AS xxx
For example:
CREATE OR REPLACE TYPE address_t AS OBJECT (
ADDID NUMBER(10,0),
STREET VARCHAR2(40),
ZIP VARCHAR2(5),
CITY VARCHAR2(40)
)
/
CREATE OR REPLACE TYPE addresses_nt AS TABLE OF address_t
/
CREATE OR REPLACE TYPE invoicepos_t AS OBJECT (
ARTID NUMBER(10,0),
AMOUNT NUMBER(10,0)
)
/
CREATE OR REPLACE TYPE invoicepos_nt AS TABLE OF invoicepos_t
/
CREATE OR REPLACE TYPE customer_t AS OBJECT (
CUSID NUMBER(10,0),
FIRSTNAME VARCHAR2(30),
LASTNAME VARCHAR2(30),
ADDRESSES addresses_nt
)
/
CREATE OR REPLACE TYPE invoice_t AS OBJECT (
INVOICEID NUMBER(10,0),
CUSTOMER REF customer_t,
ADDID NUMBER(10,0),
POSITIONS invoicepos_nt
)
/
CREATE TABLE customer OF customer_t
NESTED TABLE ADDRESSES STORE AS all_adresses RETURN AS VALUE
/
CREATE TABLE invoices OF invoice_t
NESTED TABLE POSITIONS STORE AS all_invoicepos RETURN AS VALUE
/
As far as I can tell, the only difference is that LOCATORs are a bit faster than VALUEs. But that doesn't make sense and I'm hoping somebody will prove me wrong; there's almost never a "fast=true" switch.
According to the SQL Language Reference:
RETURN [AS] Specify what Oracle Database returns as the result of a query.
VALUE returns a copy of the nested table itself.
LOCATOR returns a collection locator to the copy of the nested table.
The locator is scoped to the session and cannot be used across sessions. Unlike a LOB locator, the collection locator cannot be used to modify the collection instance.
This implies that LOCATORs are read-only. But on 11gR2 a LOCATOR can still be modified.
The Object Relational Developer's Guide also discusses LOCATORs, but does not mention any downsides to using them.
Sample Schema
CREATE OR REPLACE TYPE invoicepos_t AS OBJECT (
ARTID NUMBER(10,0),
AMOUNT NUMBER(10,0)
)
/
CREATE OR REPLACE TYPE invoicepos_nt AS TABLE OF invoicepos_t
/
create table invoices_val
(
INVOICEID NUMBER,
POSITIONS invoicepos_nt
)
NESTED TABLE POSITIONS STORE AS all_invoicepos_val RETURN AS VALUE
/
create table invoices_loc
(
INVOICEID NUMBER,
POSITIONS invoicepos_nt
)
NESTED TABLE POSITIONS STORE AS all_invoicepos_loc RETURN AS locator
/
insert into invoices_val values(1, invoicepos_nt(invoicepos_t(1,1)));
insert into invoices_loc values(1, invoicepos_nt(invoicepos_t(1,1)));
insert into invoices_def values(1, invoicepos_nt(invoicepos_t(1,1)));
commit;
Compare performance and funcionality
--Value: 1.0 seconds
declare
v_positions invoicepos_nt;
begin
for i in 1 .. 10000 loop
select positions
into v_positions
from invoices_val;
end loop;
v_positions.extend;
v_positions(2) := invoicepos_t(3,3);
update invoices_val set positions = v_positions;
end;
/
--Locator: 0.8 seconds
declare
v_positions invoicepos_nt;
begin
for i in 1 .. 10000 loop
select positions
into v_positions
from invoices_loc;
end loop;
v_positions.extend;
v_positions(2) := invoicepos_t(3,3);
update invoices_loc set positions = v_positions;
end;
/

I am trying to use a Subtype Object in place of a Supertype object but it is not working?

I have created two objects T_PERSONS,T_BUSINESS_PERSON where T_BUSINESS PERSON is a subtype and T_PERSONS is a supertype.
---Creating T_PERSONS OBJECT---
CREATE OR REPLACE
TYPE T_PERSONS AS OBJECT
( id integer,
first_name varchar2(10),
last_name varchar2(10),
dob DATE,
phone varchar2(12),
address t_address,
) NOT FINAL;
---Creating T_BUSINESS_PERSON OBJECT---
CREATE TYPE t_business_person UNDER t_persons
(title varchar2(20),
company varchar2(20)
);
Now I created an object table object_customers
CREATE TABLE object_customers OF t_persons
INSERTING DATA INTO object_customers
INSERT INTO object_customers VALUES
(t_persons(1,'Jason','Bond','03-APR-1955','800-555-1211',
t_address('21 New Street','Anytown','CA','12345')
));
in this case,data has been inserted properly
INSERT INTO object_customers VALUES
(t_business_person(2,'Steve','Edwards','03-MAR-1955','800-555-1212',
t_address('1 Market Street','Anytown','VA','12345'),'Manager','XYZ Corp'
));
Now in this case an error has occured
Error-attribute or element value is larger than specified in type.
Please Help.
The second insertion will work only if you create the table as follows:
CREATE TABLE object_customers OF t_business_person;
Click here to read more about NOTFINAL clause.

Resources