-- This is an introduction to objects in Oracle. create type address_type as object( street varchar2(10), zip number(5)) / create type person_t as object ( name varchar2(10), address address_type, -- SEE ABOVE birthyear number, member function age(empid in number) return number, -- ^^^ method header pragma restrict_references(age, WNDS) -- This means ) -- Don't let it change the DB!! / -- Write No Database State. -- Note: You can only use a method in a SELECT statement if it is WNDS. -- There is also RNDS. That means: No queries allowed. -- The method implementation comes at the end. -- Member procedures are also possible. create table employees ( person person_t, -- defined above employeeid number(4) ) / insert into employees values (person_t('Jones', -- use type as constructor address_type('123 Main', 07102), -- nested constructor 1971), 4412) / insert into employees values (person_t('Smith', address_type('43 Elm', 07112), 1945), 4413) / -- The following shows you your objects. select * from user_objects / -- Now we can define select statements for an object. select * from employees / select c.person.name --table/column/field in object from employees c / select c.person.address.street -- table/column/field/nested field from employees c / select c.person.address -- table/column/field from employees c / select c.person.name, c.person.address.street from employees c where c.person.name = 'Jones' / -- Now write the method! -- The following works only in 2016. -- At the end is a "year safe" method. create or replace type body person_t as member function age(empid in number) return number is diff employees.person.birthyear%type; -- The variable "diff" -- is the same type as the -- column birthyear in -- table employees !! cursor joe is (select e.person.birthyear from employees e where e.employeeid = empid); begin open joe; fetch joe into diff; -- Get birthyear diff := 2016 - diff; -- Compute age close joe; return diff; -- Return age end; end; / -- Now use the method in a select statement. select c.employeeid, c.person.birthyear, c.person.age(c.employeeid) from employees c / select c.person.age(4413) from employees c / select c.person.age(4413) from employees c where c.employeeid=4413 / select c.person.age(4412) from employees c where c.employeeid=4412 / select c.person.age(4411) from employees c where c.employeeid=4411 / select unique c.person.age(4413) from employees c / select distinct c.person.age(4413) from employees c / -- We need the unique, because really, this is executed -- once for every row of the table... -- If that seems strange, remember what this does: -- select 3*4 from employees; -- We have achieved what we wanted. -- We have written a method. -- Used in a select statement. select c.employeeid, c.person.age(c.employeeid) from employees c -- shows all correctly / -- ------------------------ -- Now inheritance -- Here is a class. -- It is meant to describe people at a university. create type parenttype as object ( name varchar2(50), description varchar2(1000), id number(2) ) NOT INSTANTIABLE NOT FINAL; -- NOT FINAL means it can have children. It's not a leaf. -- NOT INSTANTIABLE means that you cannot create instances. -- If you leave out the NOT FINAL you get a compiler error. Because if you cannot create instances AND you cannot create children the type is useless. -- If you leave out the NOT INSTANTIABLE, that compiles correctly. Because you CAN create children for a type that has instances. -- Here is a subclass. create type childtype UNDER parenttype (department varchar2(20) ) NOT FINAL / -- Note: overriding is not permitted in inheritance [First surprise. When I created a grandchild type I got an error message. And YET it created the grandchild type.] create type grandchildtype UNDER childtype (specialization varchar2(20)) / -- Here is a table with subclass data. create table inheri (oneobj childtype) -- Now we insert data. insert into inheri values (childtype('tom','teacher',12, 'cs') ) / create table inherit2 (oneobj grandchildtype) / insert into inherit2 values (grandchildtype('joe','teacher',12, 'cs', 'AI') ) / select * from inheri / select * from inherit2 / You can use constructors in WHERE of SELECT You can use constructors in SET and in WHERE of UPDATE You can use triggers with objects in tables. -- Object constructor in where clause select c.person.name, c.person.address, c.person.zip from employees c where c.person.address = ADDRESS_TYPE('123 Main', 7102); -- Update of an object column update employees c set c.person.address = ADDRESS_TYPE('123 Main', 8202) where c.person.address = ADDRESS_TYPE('49 Elm', 7102) / -- Trigger on object column create or replace trigger jennifer after update on employees -- Note AFTER trigger for each row begin dbms_output.put_line('Here I am after changing'); end; / -- This update works together with the above: update employees c set c.person.address = ADDRESS_TYPE('68 Mull', 9202) where c.person.address = ADDRESS_TYPE('123 Main', 7102) -- Multiple inheritance is not possible -- The above method is not "year safe". Now comes the year-safe version. select sysdate from dual / select to_char(sysdate, 'YYYY') from dual / select to_char(sysdate, 'YYYYMMDD') from dual / select to_char(sysdate, 'YYYY-MM-DD') from dual / select to_char(sysdate, 'HH-MI-SS') from dual / begin dbms_output.put_line( to_char(sysdate, 'YYYY')); end; / For more look here: http://www.techonthenet.com/oracle/functions/to_date.php Don't really need a second cursor!!! Because only one value is returned. create or replace type body person_t as member function age(empid in number) return number is diff number; nowyear varchar2(4); cursor joe is (select e.person.birthyear -- I had a wrong column.. no error msg from employees e where e.employeeid = empid); begin select to_char(sysdate, 'YYYY') into nowyear from dual; open joe; fetch joe into diff; close joe; diff := nowyear - diff; return diff; end; end; / ========================== drop table inheri / drop table inherit2 / drop type grandchildtype / drop type childtype / drop type parenttype /