PL/SQL inherit rowtype - oracle

I know Oracle PL/SQL allows to create object sub type using the "under" keyword. But is it possible to create a subtype that inherit the RowType of a particular table?
For example, if there is a table named Customer and I want to create an object type that has all attributes in Customer table with extra fields.
I tried:
create or replace type t_sub_type as object under Customer%RowType (
price NUMBER
);
Of course, the code fails to compile. So is there any way to achieve this?

Not unless customer happens to be an object table. If customer is a regular old table, customer%rowtype is a record, not an object, so it cannot be inherited from. If you created an object type customer_typ and created a table customer of those object types, then you could create a subtype of customer_typ. Something like
SQL> ed
Wrote file afiedt.buf
1 create type customer_typ
2 as object (
3 name varchar2(100),
4 address varchar2(1000),
5 phone varchar2(30)
6 )
7* not final
SQL> /
Type created.
SQL> create table customer_tbl of customer_typ;
Table created.
SQL> create type subcustomer_typ
2 under customer_typ (
3 newColumn number
4 );
5 /
Type created.
SQL> desc subcustomer_typ;
subcustomer_typ extends SCOTT.CUSTOMER_TYP
Name Null? Type
----------------------------------------- -------- ----------------------------
NAME VARCHAR2(100)
ADDRESS VARCHAR2(1000)
PHONE VARCHAR2(30)
NEWCOLUMN NUMBER
Of course, I'm hard pressed to imagine a case where this would make a great deal of sense. But it is possible. If you can describe why you want to inherit from a %rowtype record, we may be able to suggest some alternative approaches.

Related

Oracle Object Type and Object Table

I have created an object type and a table. I would like to know how select, insert, update and delete operation on it.
create table employee_info (
empid number,
emp_name varchar2(50),
department varchar2(20),
designation varchar2(50),
salary number
);
create type employee_info_obj is object (
empid number,
department varchar2(50),
designation varchar2(50),
salary number
);
create type employee_info_obj_t is
table of employee_info_obj ;
You have only created an object type and an unrelated database table. If you want a database table based on the type, you need to create one:
create table employee_info of employee_info_obj;
While it can be nice in certain programming scenarios to have a type synced to a table, there are some downsides such as it being harder to add columns later, and third party tool support since the object table will not be listed in user_tables but only in user_object_tables and user_all_tables, so I would question the usefulness of this approach.
dbFiddle

Oracle TYPE declaration throwing error PLS-00201 - identifier must be declared

I created a Object Type successfully using below command:
create or replace
TYPE "SharedAccountRecType" AS object(
account_id NUMBER(11),
share_by_id NUMBER(11),
share_to_id NUMBER(11)
);
Then I tried to create another Type as a table of above successfully created Object Type. Below command is throwing error:
create or replace
TYPE "SharedAccountRecTypeCollection"
as table of SharedAccountRecType
Error: PLS-00201: identifier 'SHAREDACCOUNTRECTYPE' must be declared.
Both above commands were executed using same Oracle user, one after the other. Please help.
If you use double quotes, Oracle will create a type with the exact name you typed, case sensitive.
For example:
SQL> create or replace
2 TYPE "SharedAccountRecType" AS object(
3 account_id NUMBER(11),
4 share_by_id NUMBER(11),
5 share_to_id NUMBER(11)
6 );
7 /
Type created.
SQL> create or replace
2 TYPE SharedAccountRecType AS object(
3 account_id NUMBER(11),
4 share_by_id NUMBER(11),
5 share_to_id NUMBER(11)
6 );
7 /
Type created.
SQL> select type_name
2 from user_types
3 where upper(type_name) = 'SHAREDACCOUNTRECTYPE';
TYPE_NAME
------------------------------
SHAREDACCOUNTRECTYPE
SharedAccountRecType
SQL>
Given this, you may want to remove the double quotes from the creation of SharedAccountRecType:
create or replace TYPE SharedAccountRecType AS object ...
create or replace ... as table of SharedAccountRecType
or add them in the creation of the table type, depending whether you want case sensitive names or not
create or replace TYPE "SharedAccountRecType" AS object ...
create or replace ... as table of "SharedAccountRecType"
It is happened because you use "" in the name of type.
In Oracle names "SharedAccountRecType" and SharedAccountRecType are different.
Don't use name in "", because Oracle threat names in "" as case-sensitive, but name without "" as case-unsensitive uppercase.

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.

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;
/

Subtype Supertype with Oracle Object Type Creation. Limit on the number of subtypes?

I have run into an issue when creating a object type in Oracle 10g that inherits from a supertype. We currently have many object types that inherit from this supertype and recently the compiler started throwing the following errors
ORA-30745: error occured while trying to add column "SYS_NC_ROWINFO$" in table "DATA_CACHE.CACHE_ENTRIES"
ORA-01792: maximum number of columns in a table or view is 1000
Is there a cap on the number of subtypes you can generate that inherit from a supertype?
When you create tables with columns based on user-defined types, Oracle creates additional "secret" columns for you under the covers. For example:
SQL> create type emp_data_t as object (empno number, ename varchar2(30));
2 /
Type created.
SQL> create table emp_data_table (id int, emp_data emp_data_t);
Table created.
This table appears to have 2 columns:
SQL> desc emp_data_table
Name Null? Type
-------------------------- -------- ------------------------
ID NUMBER(38)
EMP_DATA EMP_DATA_T
... but it really has four:
SQL> select name
2 from sys.col$
3 where obj# = (select object_id
4 from user_objects
5 where object_name='EMP_DATA_TABLE');
NAME
------------------------------
ID
EMP_DATA
SYS_NC00003$
SYS_NC00004$
As you have seen, Oracle has a limit of 1000 columns per table. This limit will include any of these hidden columns derived from types and supertypes. It looks like your table has exceeded this limit.
use command:
PURGE RECYCLEBIN;

Resources