Object types
An Oracle database is an object-relational hybrid which means that it
supports both objects and the traditional relational database features
- tables and columns.
By providing support for objects in the database Oracle eliminates the
need for object-oriented applications to translate their object data
models into relational models as well as the need at run-time to map
object access requests to relational table access.
Oracle
Tips
& Tricks to
SKYROCKET Your Career!
If
you're not
already a subscriber to Oracle
Tips and Tricks,
you're missing out on a myriad of tips and techniques to help
you become a better, faster, smarter developer. Subscribe now and ignite your
career.
An Oracle data type that is an object has 3 parts:
- a name (which must be unique within the schema)
- attributes (which define the object's
properties and may be of built-in or other user-defined types)
- and methods which are procedures or functions
written in PL/SQL that implement operations that the object can perform.
New object types are created using the
CREATE
OR REPLACE TYPE statement in SQL. This defines the name of
the object and its attributes. Methods are defined as part of the
CREATE
TYPE BODY statement;
For example to create new type called PERSON you might define
it like this:
CREATE
OR REPLACE TYPE person IS OBJECT
(first_name VARCHAR2(30);
last_name VARCHAR2(30);
address address_type,
MEMBER FUNCTION name RETURN VARCHAR2);
Where address_type is another user-defined type and the function
name
is a method the detail of which is defined by the
CREATE
TYPE BODY statement like this:
CREATE
TYPE BODY person IS
MEMBER FUNCTION name RETURN VARCHAR2 IS
BEGIN
RETURN first_name||' '||last_name;
END;
END;
The methods that can be defined for object Oracle data types include:
- a CONSTRUCTOR
function which is used to instantiate an object of that type at run-time
- a MAP
function which returns the relative position of a given object instance
in the ordering of all instances of the object (i.e. this person is #3)
- an ORDER
function which returns a value of -1, 0 or 1 to indicate that the
object instance is less than, equal to, or greater than
another specified object instance
- STATIC methods (these cannot reference
implicitly the object with which they are associated)
- MEMBER methods (these can reference implicitly
the object with which they are associated)
Note that an object type can have either a
MAP
function or an
ORDER
function, not both.
It is also worth noting that object types can be used in relational
tables as well as object tables.
For example, we could use the Oracle data type Person that we've just
defined in a relational table declaration like this:
CREATE
TABLE customers (cust_id Number(12), cust person);
To create an object table using this type the declaration would be like
this:
CREATE
TABLE customers OF person;
In this case, each row of the table contains an instance of
type Person. The instance is automatically assigned a unique,
system-generated object identifier when a row is inserted.
Nested Tables
Nested table Oracle data types are useful where you have a master-detail/parent-child relationship between 2 entities and where
the number of detail records is unknown. A good example of this is invoices and invoice lines.
For example, to create, an invoice table with a
nested invoice-line table, first define the object
type for the invoice details:
CREATE
OR REPLACE TYPE inv_dtl AS OBJECT
(
Inv_line_id NUMBER(5),
Item_desc VARCHAR2(120),
Item_Amt
NUMBER(6,2)
);
Next, define the table type based on the object
type:
CREATE
OR REPLACE TYPE inv_dtl_tab AS TABLE OF inv_dtl;
Finally define the parent table with the nested
table:
CREATE
TABLE invoice(
Invoice_id NUMBER(5),
Cust_id NUMBER(6),
Total
NUMBER(9,2),
Lines
inv_dtl_tab
)
NESTED
TABLE lines STORE AS invoice_lines;
The STORE AS clause defines the name of the segment used
to hold the nested table and is necessary because nested tables are
stored in a different segment to (but in the same tablespace as) the
main table.
To access a nested table, you have to un-nest the table:
SELECT invoice_id, inv_line_id, item_desc, item_amt FROM
invoice i, TABLE(i.lines)WHERE invoice_id = 1;
VARRAYS
A VARRAY is an Oracle data type that is useful when the maximum number of detail records is
small and
is known in advance (such as a list of phone numbers for a customer
e.g. office,
home and mobile). Note that there is no storage clause for the
varray, because
they are stored in line.
CREATE TYPE phone_no_type AS OBJECT ( Desc VARCHAR2(20) ,Phone_no VARCHAR2(20) );CREATE TYPE phone_no_list AS VARRAY(3) OF phone_no_type;CREATE OR REPLACE TYPE cust AS OBJECT ( Cust_id NUMBER(12) ,Name VARCHAR2(75) ,Phone_nos phone_no_list) );The elements of a varray cannot be accessed individually using SQL,
but
they can be accessed in PL/SQL and 3GLs.
REF Data Types
The REF Oracle data type is used to establish a relationship from
one object to another by storing the object identifier (the object's
unique identifier) of another object. This relationship is defined by
means of a reference in the object table definition. This acts like a
foreign key, linking one object to another object in the database (via
the unique object identifier – the object’s primary key). Oracle uses
the link automatically to perform the same function as a join between
relational tables.
For example consider a new object called inv which in a
relational database
would have a foreign key relationship to the customer table. In
object terms
this becomes a new object referencing an existing object as follows:
CREATE OR REPLACE TYPE inv AS OBJECT
(
Invoice_id NUMBER(12)
,Client REF cust
,Total NUMBER(9,2));
CREATE TABLE invoice OF inv (id PRIMARY KEY);
When a REF value points to a nonexistent object, the REF
is said to be "dangling" (not the same as a null REF). The condition IS [NOT] DANGLING is used to determine whether or not a REF is
dangling.
For example, using
the object Oracle data type CUST as just defined and the table INVOICE
the following statement would retrieve all of the names of customers
who have a record in the table.
SELECT i.client.name FROM invoice i WHERE i.client IS NOT DANGLING;