General Information |
Object types and other user-defined types allow for the definition of data types that model the structure and behavior of the data in an application. |
Related Data Dictionary Objects | collection$ source$ type$
dba_coll_types | all_coll_types | user_coll_types | dba_dependencies | all_dependencies | user_dependencies | dba_source | all_source | user_source | dba_types | all_types | user_types | dba_varrays | all_varrays | user_varrays |
|
System Privileges Related To Types | CREATE TYPE CREATE ANY TYPE DROP ANY TYPE |
|
Create Type Header |
Single Column Object Declaration | CREATE OR REPLACE TYPE <type_name> AUTHID <CURRENT USER | DEFINER> AS OBJECT ( <attribute> <attribute data_type>, <inheritance clause>, <subprogram spec>) <FINAL | NOT FINAL> <INSTANTIABLE | NOT INSTANTIABLE>; / |
CREATE OR REPLACE TYPE ssn_t AS OBJECT ( ssn_type CHAR(11)); /
-- examine type definition SELECT * FROM user_source WHERE name = 'SSN_T';
CREATE TABLE ssn ( per_id NUMBER(10), per_ssn ssn_t);
desc SSN
-- examine table columns SELECT column_name, data_type FROM user_tab_columns WHERE table_name = 'SSN';
INSERT INTO ssn VALUES (1, '123-45-6789');
INSERT INTO ssn VALUES (1, ssn_t('123-45-6789'));
SELECT * FROM ssn;
UPDATE ssn SET per_ssn = ssn_t('111-22-3333');
SELECT * FROM ssn;
INSERT INTO ssn VALUES (1, ssn_t('999-88-7777'));
SELECT * FROM ssn;
UPDATE ssn SET per_ssn = ssn_t('456-56-0841') WHERE per_ssn = ssn_t('111-22-3333');
SELECT * FROM ssn; |
Multicolumn Object Declaration | CREATE OR REPLACE TYPE <type_name> AS OBJECT ( <column_name> <data_type>, ..., <column_name> <data_type>); / |
CREATE OR REPLACE TYPE phone_t AS OBJECT ( a_code CHAR(3), p_number CHAR(8)); /
-- examine type definition SELECT * FROM user_source WHERE name = 'PHONE_T';
CREATE TABLE phone ( per_id NUMBER(10), per_phone phone_t);
set describe depth all
desc phone
-- examine table columns col data_type format a15 col data_type_owner format a15
SELECT column_name, data_type, data_type_mod, data_type_owner FROM user_tab_columns WHERE table_name = 'PHONE';
INSERT INTO phone (per_id, per_phone) VALUES (1, phone_t('206', '555-1212'));
INSERT INTO phone (per_id, per_phone) VALUES (2, phone_t('212', '123-4567'));
SELECT * FROM phone;
SELECT per_id FROM phone;
SELECT per_id, per_phone FROM phone;
-- selective select SELECT * FROM phone p WHERE p.per_phone.a_code = '206';
SELECT p.per_phone.p_number FROM phone p WHERE p.per_phone.a_code = '206';
-- selective update UPDATE phone p SET p.per_id = 9 WHERE p.per_id = 1;
SELECT * FROM phone;
UPDATE phone p SET p.per_phone.a_code = '303' WHERE p.per_phone.a_code = '206';
SELECT * FROM phone;
-- selective delete DELETE FROM phone p WHERE p.per_id = 2;
SELECT * FROM phone;
DELETE FROM phone p WHERE p.per_phone.a_code = '206';
SELECT * FROM phone; |
|
Create Subtype |
| CREATE OR REPLACE TYPE <type_name> AUTHID <CURRENT USER | DEFINER> UNDER <supertype_name>, <attribute> <data_type>, <inheritance clause> <subprogram spec>, <pragma clause>) <FINAL | NOT FINAL> <INSTANTIABLE | NOT INSTANTIABLE>; / |
-- create object supertype CREATE OR REPLACE TYPE person_typ AS OBJECT ( ssn NUMBER(9), name VARCHAR2(30), address VARCHAR2(100)) NOT FINAL; /
-- derive collection type from supertype CREATE OR REPLACE TYPE person_tab_typ AS TABLE OF person_typ; /
-- derive object subtype from object supertype CREATE OR REPLACE TYPE student_typ UNDER person_typ ( deptid NUMBER, major VARCHAR2(30)) NOT FINAL; /
-- derive collection type from subtype CREATE OR REPLACE TYPE student_tab_typ AS TABLE OF student_typ; /
-- create nested table from the two collection CREATE TABLE test ( regular_field DATE, person_nested_tab person_tab_typ, student_nested_tab student_tab_typ) NESTED TABLE person_nested_tab STORE AS per_tab NESTED TABLE student_nested_tab STORE AS stu_tab;
desc test desc per_tab desc stu_tab |
|
Create Type Body |
Create A Collection From An Object. | |
CREATE OR REPLACE TYPE people_typ AS OBJECT ( last_name VARCHAR2(25), department_id NUMBER(4), salary NUMBER(8,2)); /
CREATE OR REPLACE TYPE people_tab_typ AS TABLE OF people_typ; /
CREATE TABLE hr_info ( department_id NUMBER(4), location_id NUMBER(4), manager_id NUMBER(6), people people_tab_typ) NESTED TABLE people STORE AS people_stor_tab;
DESC hr_info
INSERT INTO hr_info VALUES (100, 1800, 999, people_tab_typ());
INSERT INTO hr_info VALUES (200, 2000, 881, people_tab_typ());
SELECT * FROM hr_info; |
Create Type As Variable | |
|
Create Type As Variable In Package Header | |
|
|
Row Data Type Declaration | |
|
Array Data Type Declaration | |
TYPE ARRAY IS TABLE OF all_objects%ROWTYPE; l_data ARRAY; |
|
Create Type Header As Database Object |
Type Collection Of A User Defined Object Data Type | CREATE OR REPLACE TYPE <type_name> AS TABLE OF <user_defined_data_type>; / |
CREATE OR REPLACE TYPE phones_tab_t AS TABLE OF phone_t; /
SELECT object_name, object_type FROM user_objects;
SELECT type_name, typecode FROM user_types;
SELECT type_name, coll_type FROM user_coll_types; |
Heap Table Of A User Defined Data Object Type | CREATE TABLE <table_name> column_name <user_defined_data_type); |
CREATE TABLE test ( person_id NUMBER(10), per_phones phone_t);
desc test
COL data_type FORMAT a40
SELECT column_name, data_type FROM user_tab_columns WHERE table_name = 'TEST'; |
Heap Table Of With A User Defined Data Object Type As A Nested Table | CREATE TABLE <table_name> ( column_name <user_defined_data_type>) NESTED TABLE <column_name> STORE AS <name_of_nested_table>; |
CREATE TABLE person ( person_id NUMBER(10), first_name VARCHAR2(25), middle_inits VARCHAR2(4), last_name VARCHAR2(25), name_suffix VARCHAR2(5), title_1 VARCHAR2(5), title_2 VARCHAR2(5), dob DATE, ssn VARCHAR2(11), address_id NUMBER(10), person_phones phones_tab_t, email_address VARCHAR2(30), ok_to_mail VARCHAR2(1), active_flag VARCHAR2(1)) NESTED TABLE person_phones STORE AS phones_tab TABLESPACE uwdata;
desc person
COL table_name FORMAT a30 COL table_type_name FORMAT a20 COL parent_table_column FORMAT a25
SELECT table_name, table_type_name, parent_table_column FROM user_nested_tables; |
Insert Into Parent And Nested Table | INSERT INTO <table_name> (<column_name_list>) VALUES (<list_of_column_values>, <table_type_constructor>(<type_constructor(<type_values>))); |
INSERT INTO person (person_id, last_name, person_phones) VALUES (1, 'Morgan', phones_tab_t(phone_t('C', '206-555-1212')));
INSERT INTO person (person_id, last_name, person_phones) VALUES (2, 'Cline', phones_tab_t(phone_t('C', '425-555-1212'))); |
Insert Into Nested Table | INSERT INTO TABLE ( SELECT <nested_table_column_name> FROM <table_name> WHERE <column_name> <condition <value>) VALUES (<column_value>, <column_value>); |
INSERT INTO TABLE( SELECT person_phones FROM person WHERE person_id = 1) VALUES ('H','206-987-6543');
SELECT t1.person_id, last_name, t2.* FROM person t1, TABLE(t1.person_phones) t2; |
Select From Nested Table | SELECT <column_name_list> FROM <table_name>; |
SELECT * FROM person; |
Select From Nested Table With TABLE Function | SELECT <column_name_list, <tested_table_column_list> FROM <table> <alias>, TABLE (<alias.nested_table_name> <alias>; |
SELECT person_id, last_name, t2.* FROM person t1, TABLE(t1.person_phones) t2; |
Update All Nested Table Rows | UPDATE person SET person_phones = <table_constructor>(<type_constructor(<column_values>)); |
UPDATE person SET person_phones = phones_tab_t(phone_t('H', '360-555-1212')) WHERE person_id = 2; |
Update Selected Nested Table Rows | UPDATE TABLE ( <nested_select_statment>) <alias> SET <nested_column> = <value> WHERE <alias.nested_column_name> <condition> <value>; |
UPDATE TABLE ( SELECT person_phones FROM person WHERE person_id = 1) p SET p.phone_type = 'W' WHERE p.phone_number = '206-987-6543';
SELECT t1.person_id, last_name, t2.* FROM person t1, TABLE(t1.person_phones) t2; |
Delete From Nested Table | DELETE TABLE ( <nested_select_statment>) <alias> WHERE <alias.nested_column_name> <condition> <value>; |
DELETE TABLE ( SELECT person_phones FROM person WHERE person_id = 1) p WHERE p.phone_number = '206-987-6543'; |
SELECT a_code FROM TABLE ( SELECT per_phone FROM phone h) p WHERE 1=1; |
Create Type Header As Database Varray |
User Defined Object Data Type | -- same as above
CREATE OR REPLACE TYPE <type_name> AS OBJECT ( <column_name> <data_type>); / |
CREATE OR REPLACE TYPE title_t AS OBJECT ( title_name VARCHAR2(5)); /
SELECT type_name, typecode FROM user_types; |
Define VARRAY Of Object Type | CREATE TYPE TitleList AS VARRAY(<integer>) OF <data_type>; /
SELECT type_name, typecode FROM user_types; |
CREATE TYPE TitleList AS VARRAY(3) OF title_t; /
SELECT type_name, typecode FROM user_types; |
Heap Table With Nested Varray | CREATE TABLE <table_name> ( column_name varray_name); |
DROP TABLE person;
CREATE TABLE person ( person_id NUMBER(10), first_name VARCHAR2(25), middle_inits VARCHAR2(4), last_name VARCHAR2(25), name_suffix VARCHAR2(5), person_titles title_t, dob DATE, ssn VARCHAR2(11), address_id NUMBER(10), person_phones phones_tab_t, email_address VARCHAR2(30), ok_to_mail VARCHAR2(1), active_flag VARCHAR2(1)) NESTED TABLE person_phones STORE AS phones_tab TABLESPACE uwdata;
desc person
COL parent_table_column FORMAT a30
SELECT parent_table_name, parent_table_column, type_name FROM user_varrays; -- note there is no record |
Insert Into Parent, Varray, And Nested Table | INSERT INTO <table_name> (<column_name_list>) VALUES (<list_of_column_values>, <varray_constructor>(<varray_values>) <table_type_constructor>(<type_constructor(<type_values>))); |
INSERT INTO person (person_id, last_name, person_titles, person_phones) VALUES (1, 'Morgan', title_t('PhD'), phones_tab_t(phone_t('C', '206-555-1212')));
INSERT INTO person (person_id, last_name, person_titles, person_phones) VALUES (2, 'Cline', title_t('MD'), phones_tab_t(phone_t('C', '425-555-1212'))); |
Insert Into Nested Varray | |
COL person_titles FORMAT a20
SELECT t1.person_id, last_name, person_titles, t2.* FROM person t1, TABLE(t1.person_phones) t2; |
Select From Nested Table | SELECT <column_name_list> FROM <table_name>; |
SELECT person_id, last_name, person_titles, person_phones FROM person; |
Select From Nested Table With TABLE Function | SELECT <column_name_list, <tested_table_column_list> FROM <table> <alias>, TABLE (<alias.nested_table_name> <alias> |
SELECT person_id, last_name, t2.* FROM person t1, TABLE(t1.person_phones) t2; |
Update All Nested Table Rows | UPDATE person SET person_phones = <table_constructor>(<type_constructor(<column_values>)); |
UPDATE person SET person_phones = phones_tab_t(phone_t('H', '360-555-1212')) WHERE person_id = 2; |
Update Selected Nested Table Rows | UPDATE TABLE ( <nested_select_statment>) <alias> SET <nested_column> = <value> WHERE <nested_column_name> <condition> <value> |
UPDATE TABLE ( SELECT person_phones FROM person WHERE person_id = 1) p SET p.phone_type = 'W' WHERE p.phone_number = '206-987-6543';
SELECT t1.person_id, last_name, t2.* FROM person t1, TABLE(t1.person_phones) t2; |
Delete From Nested Table | DELETE TABLE ( <nested_select_statment>) <alias>
|
DELETE TABLE ( SELECT person_phones FROM person WHERE person_id = 1) p WHERE p.phone_number = '206-987-6543'; |
|
Create Type Body (always as a database object) |
Create Type | CREATE OR REPLACE TYPE ssn AS OBJECT ( ssn_type CHAR(11)); / |
Create Type Specification (Header) | CREATE OR REPLACE TYPE ssn AS OBJECT ( n_ CHAR(11), CONSTRUCTOR FUNCTION ssn(n IN VARCHAR2) RETURN self AS result, MEMBER FUNCTION get_ssn RETURN CHAR); / |
Create Type Body | CREATE OR REPLACE TYPE BODY ssn IS
CONSTRUCTOR FUNCTION ssn(ssn_in IN VARCHAR2) RETURN self AS RESULT IS
BEGIN IF TRANSLATE(ssn_in, 'A0123456789', 'BAAAAAAAAAA') = 'AAA-AA-AAAA' THEN n_ := ssn_in; RETURN; ELSE RAISE_APPLICATION_ERROR(-20001, 'INVALID SSN'); END IF; END;
MEMBER FUNCTION get_ssn RETURN CHAR IS
BEGIN RETURN n_; END;
END; / |
Create Object Table | CREATE TABLE person ( per_name VARCHAR2(20), per_ssn SSN); |
Test SSN Data Type | DECLARE
myssn ssn;
BEGIN myssn := ssn(n=>'232-22-5678'); INSERT INTO person VALUES ('Morgan', myssn);
-- myssn := ssn(n=>'444=55-6789'); -- INSERT INTO person VALUES ('Morgan', myssn);
myssn := ssn(n=>'123-45-6789'); INSERT INTO person VALUES ('Cline', myssn); COMMIT; END; / |
|
Alter Type |
Alter Type Demo | ALTER TYPE <type name> ADD ATTRIBUTE (<atribute name> <data type>) CASCADE; |
CREATE OR REPLACE TYPE phone_t AS OBJECT ( a_code CHAR(3), p_number CHAR(8)) NOT FINAL; /
desc phone_t
CREATE OR REPLACE TYPE phone_t_tab AS TABLE OF phone_t; /
desc phone_t_tab
--produces an error CREATE OR REPLACE TYPE phone_t AS OBJECT ( country_code CHAR(3), area_code CHAR(3), phone_number CHAR(8)); /
ALTER TYPE phone_t ADD ATTRIBUTE (country_code CHAR(3)) CASCADE;
desc phone_t |
|
Drop Type |
Dropping a Type | DROP TYPE <type_name> |
DROP TABLE person;
DROP TYPE phones_tab_t; DROP TYPE phone_t; |
|
Type Inheritance |
Create Supertype | CREATE OR REPLACE TYPE person_typ AS OBJECT ( ssn NUMBER(9), name VARCHAR2(30), address VARCHAR2(100)) NOT FINAL; / |
Create Type From Subtype | CREATE OR REPLACE TYPE person_tab_typ AS TABLE OF person_typ; / |
Create Subtype | CREATE OR REPLACE TYPE student_typ UNDER person_typ ( deptid NUMBER, major VARCHAR2(30)) NOT FINAL; / |
Create Type From Subtype | CREATE OR REPLACE TYPE student_tab_typ AS TABLE OF student_typ; / |
Create Table With Two Nested Tables | CREATE TABLE test ( regular_field DATE, person_nested_tab person_tab_typ, student_nested_tab student_tab_typ) NESTED TABLE person_nested_tab STORE AS per_tab NESTED TABLE student_nested_tab STORE AS stu_tab;
desc test desc per_tab desc stu_tab |
Insert A Row | INSERT INTO test VALUES (SYSDATE, person_tab_typ(), student_tab_typ(student_typ(987654321, 'Cline', 'PO Box 0', 101, 'Computer Science')));
INSERT INTO test VALUES (SYSDATE, person_tab_typ(), student_tab_typ(student_typ(987654321, 'Cline', 'PO Box 0', 101, 'Computer Science'), student_typ(12345, 'Starr', '123 Main St', 102, 'Agricultureal Science')));
INSERT INTO test VALUES (TRUNC(SYSDATE), person_tab_typ(), student_tab_typ());
SELECT * FROM test;
INSERT INTO TABLE ( SELECT person_nested_tab FROM test WHERE regular_field = TRUNC(SYSDATE)) VALUES (111223456, 'Morgan', '123 Main Street');
SELECT * FROM test;
INSERT INTO TABLE ( SELECT student_nested_tab FROM test WHERE regular_field = TRUNC(SYSDATE)) VALUES (987654321, 'Cline', 'PO Box 123', 101, 'Frontal Lobotomy Can Be Fun' );
INSERT INTO TABLE ( SELECT student_nested_tab FROM test WHERE regular_field = TRUNC(SYSDATE)) VALUES (987654321, 'Cline', 'PO Box 123', 299, 'Advanced Basket Weaving');
SELECT * FROM test;
SET HEAD OFF
SELECT t1.*, t2.*, t3.* FROM test t1, TABLE(person_nested_tab) t2, TABLE(student_nested_tab) t3; |
|
Hold |
Constructor for a Nested Table | In the following example, you pass multiple elements to the constructor CourseList(), which returns a nested table containing those elements:
DECLARE
TYPE CourseList IS TABLE OF VARCHAR2(16); my_courses CourseList;
BEGIN my_courses := CourseList('Econ 2010','Acct 3401','Mgmt 3100'); END; /
Because a PL/SQL table does not have a declared maximum size, you can put as many elements in the constructor as necessary.
DECLARE
TYPE CourseList IS TABLE OF VARCHAR2(16); my_courses CourseList;
BEGIN my_courses := CourseList('Econ 2010','Acct 3401','Mgmt 3100'); my_courses := CourseList('Math 2022','Acct 3431','Mgmt 3100'); my_courses := CourseList('Phys 2299','Chem 9876'); my_courses := CourseList('Food 9999'); my_courses := CourseList('Orcl 3456','Math 3434','Hist 1040'); END; / |
Defining a Type as a database object | CREATE OR REPLACE TYPE CourseList AS TABLE OF VARCHAR2(64); / |
Defining Types in a package header | CREATE OR REPLACE PACKAGE xyz IS
TYPE CourseList IS TABLE OF VARCHAR2(64);
TYPE PartNum IS TABLE OF parent.part_num%TYPE INDEX BY BINARY_INTEGER;
END; / |
|
set serveroutput on
DECLARE TYPE demo IS TABLE OF VARCHAR2(32767); x demo; BEGIN x := demo(RPAD('X', 32766, 'Z')); dbms_output.put_line(x(1)); END; / |
|
CREATE TYPE data_typ AS OBJECT (year NUMBER, MEMBER FUNCTION prod(invent NUMBER) RETURN NUMBER);
CREATE TYPE BODY data_typ IS
MEMBER FUNCTION prod (invent NUMBER) RETURN NUMBER IS BEGIN RETURN (year + invent); END;
END; / |
|
CREATE TYPE person_t AS OBJECT (name VARCHAR2(100), ssn NUMBER) NOT FINAL;
CREATE TYPE employee_t UNDER person_t (department_id NUMBER, salary NUMBER) NOT FINAL;
CREATE TYPE part_time_emp_t UNDER employee_t (num_hrs NUMBER); |
|
CREATE OR REPLACE TYPE emp_type AS OBJECT ( eno NUMBER, ename CHAR(31) , eaddr addr_t); |
CREATE OR REPLACE TYPE phone_t AS OBJECT ( a_code CHAR(3), p_number CHAR(8)); / |
|
-- user defined data type for use by function CREATE OR REPLACE TYPE InStrTab IS TABLE OF VARCHAR2(4000); /
CREATE OR REPLACE FUNCTION contains_all (useridin dms_user.id%TYPE, stringin VARCHAR2, checkint INTEGER) RETURN INTEGER IS
i BINARY_INTEGER; my_table dbms_utility.uncl_array; stringary InStrTab;
BEGIN -- convert stringin of domain ids into a PL/SQL table dbms_utility.comma_to_table(stringin, i, my_table); -- initialize a collection stringary := InStrTab(''); -- extend the collection to the size of the PL/SQL table stringary.EXTEND(my_table.COUNT);
-- for each element in the PL/SQL table FOR j IN 1 .. my_table.COUNT LOOP -- remove the double-quotes my_table(j) := TRANSLATE(my_table(j), 'A"', 'A'); -- assign it to an element in the array stringary(j) := my_table(j); END LOOP;
-- check the count of array elements found in the user_domain_map table SELECT COUNT(*) INTO i FROM zuser_domain_map WHERE user_id = useridin AND domain_id IN ( SELECT column_value FROM TABLE(CAST(stringary AS InStrTab)));
-- compare the number found agains the checksum IF i >= checkint THEN RETURN 1; ELSE RETURN 0; END IF; END contains_all; /
How to test:
SELECT contains_all(121, '"200","201","207"',3) FROM dual; |