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

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;

Related

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.

PL/SQL inherit rowtype

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.

Can I make a table of objects that have nested tables as attributes?

Here is a snippet of my OR schema:
CREATE TYPE artist_table_type AS TABLE OF REF artist_type;
/
CREATE TYPE track_type AS OBJECT (
title VARCHAR(1000),
duration INT,
release_date DATE,
producers artist_table_type,
MEMBER FUNCTION getProducers RETURN artist_table_type,
MEMBER FUNCTION getRemixers RETURN artist_table_type
);
/
CREATE TABLE track_obj_table OF track_type;
When I attempt to run this, I get the error:
CREATE TABLE track_obj_table OF track_type
*
ERROR at line 1:
ORA-22913: must specify table name for nested table column or attribute
I suspect that this is because of the table type in the track_type object?
It just means you have to provide the storage clause for the nested table:
SQL> CREATE TABLE track_obj_table OF track_type;
CREATE TABLE track_obj_table OF track_type
*
ERROR at line 1:
ORA-22913: must specify table name for nested table column or attribute
SQL> CREATE TABLE track_obj_table OF track_type
2 NESTED TABLE producers STORE AS producers_nt
3 /
Table created.
SQL> desc track_obj_table
Name Null? Type
----------------------------------------- -------- -------------------------
TITLE VARCHAR2(1000)
DURATION NUMBER(38)
RELEASE_DATE DATE
PRODUCERS ARTIST_TABLE_TYPE
SQL>

Setting the primary key of a object type table in Oracle

I have two Oracle questions.
How can I set the primary key of a table when the table is made up of an object type? e.g.
CREATE TABLE object_names OF object_type
I have created a Varray type,
CREATE TYPE MULTI_TAG AS VARRAY(10) OF VARCHAR(10);
but when I try to do
SELECT p.tags.count FROM pg_photos p;
I get an invalid identifier error on the "count" part. p.tags is a MULTI_TAG, how can I get the number of elements in the MULTI_TAG?
First of all I wouldn't recommend storing data in Object tables. Objects are a great programmatic tool but querying Object tables leads to complicated SQL. I would advise storing your data in a standard relationnal model and using the objects in your procedures.
Now to answer your questions:
A primary key should be immutable, so most of the time an Object type is inappropriate for a primary key. You should define a surrogate key to reference your object.
You will have to convert the varray into a table to be able to query it from SQL
For example:
SQL> CREATE TYPE MULTI_TAG AS VARRAY(10) OF VARCHAR(10);
2 /
Type created
SQL> CREATE TABLE pg_photos (ID number, tags multi_tag);
Table created
SQL> INSERT INTO pg_photos VALUES (1, multi_tag('a','b','c'));
1 row inserted
SQL> INSERT INTO pg_photos VALUES (2, multi_tag('e','f','g'));
1 row inserted
SQL> SELECT p.id, COUNT(*)
2 FROM pg_photos p
3 CROSS JOIN TABLE(p.tags)
4 GROUP BY p.id;
ID COUNT(*)
---------- ----------
1 3
2 3
1)
A primary key is a constraint, to add constrains on object tables check this link:
http://download-west.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjdes.htm#i452285
2)
The COUNT method can't be used in a SQL statement:
REF LINK IN COMMENTS
So in my case I had to do
SELECT p.pid AS pid, count(*) AS num_tags FROM pg_photos p, TABLE(p.tags) t2 GROUP BY p.pid;

What are nested table objects in Oracle?

Can someone explain what nested table objects are in Oracle ? While building an interface between to systems I discovered what was to me an odd column SYS_NC00054$. After some research I discovered that it was a nested table object from the function based index I created.
Function-based indexes are different from nested tables.
A regular index is built against actual columns ...
create index emp_job_idx on emp (job)
/
... whereas a function-based index is build on functions applied to columns. For instance we might what an index we can use when we query a date column without the time element...
create index emp_hire_idx on emp(trunc(hiredate))
/
When we query USER_IND_COLUMNS, the indexed column shows up in the first case but not in the second, because we are not indexing an actual column. What we see instead is the system generated "column'....
SQL> select index_name, column_name
2 from user_ind_columns
3 where table_name = 'EMP'
4 /
INDEX_NAME COLUMN_NAME
------------------------------ ---------------
PK_EMP EMPNO
EMP_UK ENAME
EMP_JOB_IDX JOB
EMP_HIRE_IDX SYS_NC00010$
SQL>
We can see the make-up of the index in USER_IND_EXPRESSIONS ...
SQL> select index_name, column_expression
2 from user_ind_expressions
3 where table_name = 'EMP'
4 /
INDEX_NAME COLUMN_EXPRESSION
------------------------------ --------------------
EMP_HIRE_IDC TRUNC("HIREDATE")
SQL>
Nested Tables
Nested tables are something different: they are user-defined arrays of simple or complex types. They can be used to define PL/SQL collections or columns in an ORDBMS table. Like this...
SQL> create or replace type address_t
2 as object
3 (
4 address_line_1 varchar2(70)
5 , address_line_2 varchar2(70)
6 , address_line_3 varchar2(70)
7 , address_line_4 varchar2(70)
8 , address_line_5 varchar2(70)
9 , postcode postcodestructure
10 ) final;
11 /
create or replace type address_t
*
ERROR at line 1:
ORA-02303: cannot drop or replace a type with type or table dependents
SQL>
SQL> create or replace type address_nt as table of address_t
2 /
Type created.
SQL>
SQL> create table contact_details (
2 person_id number not null
3 , email_address varchar2(254)
4 , addresses address_nt
5 )
6 nested table addresses store as nested_addresses
7 /
Table created.
SQL>
Basically, a table that has a column that stores data in the form of another table (or other complex type): A table nested inside another.
http://www.databasejournal.com/features/oracle/article.php/3788331/So-what-is-an-Oracle-Nested-Table.htm

Resources