您好,登錄后才能下訂單哦!
面向對象編程簡稱OOP編程,實際上是對現實世界事物的一種抽象的過程。它的核心是把對象的定義和實現進行區分,讓定義部分對象所具有的結構,讓實現部分根據定義部分定義的具體結構進行具體的實現。
用于生產玩具的模具叫做類,通常設計類的過程也可以稱為建模,當然這個模不是模具的模,而是對類的模型進行建模。所生產的玩具可以叫做對象,類是對象的抽象,而對象是類的具體實例。類是抽象的,不占用內存,而對象是具體的,占用存儲空間。類是用于創建對象的藍圖,它是一個定義包括在特定類型的對象中的方法和變量的軟件模版。
對類的定義是一組具有相同數據結構和相同操作的對象的集合,類的定義包括一組代表其特性的屬性。以及一組表示其執行行為的方法,類定義可以看作是一個具有相似特性與共同行為的對象模版,可以用來產生對象,而每個對象都是類的實例,都可以使用類中提供的方法,對象的具體狀態包含在對象實例變量中。
封裝:也叫做信息封裝,確保對象不會以不可預期的方式改變其他對象的內部狀態。只有在那些提供了內部狀態改變方法的對象中,才可以訪問其他內部狀態。每類對象都提供一個與其他對象聯系的接口,并規定了其他對象進行調用的方法
多態性:對象的引用和類會涉及其他許多不同類型的對象,而且引用對象所產生的結果將依據實際調用的類型
繼承性:允許在現存的對象基礎上創建子類對象,統一并增強了多態性和封裝性。典型地來說就是用類來對對象進行分組,而且還可以定義新類為現存的類的擴展,這樣就可以將類組織成樹型或網狀結構,這體現了對象的通用性。
對象類型實際上就是在上一小節中介紹的類型,類的實例就是對象。對象的類型封裝了數據結構和用于操縱這些數據結構的過程和函數,這使得通過定義對象類型就可以封裝一些較復雜的代碼,提高應用開發的效率和速度。可以在一個對象類型說明部分聲明屬性和方法,屬性不能是常數,異常,游標或類型,最大的屬性聲明數量是1000個,但是必須至少聲明一個屬性,而方法是可選的。屬性描述了對象的特性,方法則是對象類型具有的功能。在PLSQL中,方法就是一些子程序,可以是函數,也可以是過程,方法名稱不能和它的對象類型名稱和屬性名稱一樣,方法在實例級別或對象類型級別被調用。
PLSQL中對象的組成結構
PLSQL中的對象類型是一種自定義的符合類型,它的定義與包的定義非常相似
對象類型規范:是對象與應用的接口,它用于定義對象的公用屬性和方法
對象類型體:用于實現對象類型規范所定義的公用方法.
例如在定義員工對象類型時,先在對象類型規范中定義好了對象的所有屬性,以及對象可被調用的方法聲明,這些方法并沒有具體的實現部分,僅可供外部調用的方法簽名。而具體的方法體代碼實現則定義在對象類型體中。
在定義對象類型的屬性時,不能指定對象屬性的默認值,也不能指定NOT NULL選項。
PLSQL中可以定義的幾種類型的方法
1.構造方法:該方法類似于JAVA等語言中的構造函數,用來初始化一個對象類型并返回對象的實例
2.MEMBER方法:該方法允許對象的實例進行調用,在MEMBER方法中可以訪問對象實例的數據,通常稱為實例方法或成員方法
3.STATIC方法:該方法可以直接在對象類型上進行調用,它用于在對象類型上執行全局操作,通常稱為靜態方法
4.MAP方法:用于在多個對象間排序的映射方法。
5.ORDER方法:用于在兩個對象實例間排序的排序方法。
定義對象類型
對象類型包含對象類型規范和對象類型體兩大部分,因此在定義時必須先定義對象類型規范,然后再定義對象類型體.
定義employee_obj對象規范
create or replace type employee_obj as object(
empno number(4),
ename varchar2(20),
job varchar2(20),
sal number(10,2),
comm number(10,2),
deptno number(4),
MEMBER procedure change_sal(p_empno number,p_sal number),
MEMBER procedure change_comm(p_empno number,p_comm number),
MEMBER procedure change_deptno(p_empno number,p_deptno number),
MEMBER procedure get_sal(p_empno number) return number,
MEMBER procedure get_comm(p_empno number) return number,
MEMBER procedure get_deptno(p_empno number) return integer
)NOT FINAL; --指定該類可以被繼承,如果指定FINAL,表示該類無法被繼承
定義對象體
create or replace type body employee_obj
as
member procedure chang_sal(p_empno number,p_sal number)
is
begin
update emp set sal=p_sal where empno=p_empno;
end;
member procedure chang_comm(p_empno number,p_sal number)
is
begin
update emp set comm=p_comm where empno=p_empno;
end;
member procedure chang_deptno(p_empno number,p_sal number)
is
begin
update emp set deptno=p_deptno where empno=p_empno;
end;
member function get_sal (p_empno number)
return number
is
v_sal number(10,2);
begin
select sal into v_sal from emp where empno=p_empno;
return v_sal;
end;
member function get_comm(p_empno number)
return number
is
v_comm number(10,2);
begin
select comm into v_comm from emp where empno=p_empno;
RETURN v_comm;
end;
member function get_deptno(p_empno number)
return integer
is
v_deptno int;
begin
select deptno into v_deptno from emp where empno=p_empno;
return v_deptno;
end;
end;
定義屬性
屬性是對象類型特性的定義,屬性聲明是一個對象必需的,也就是說一個對象類型至少要定義一個屬性。屬性的定義與變量的定義相似,也具有名稱和數據類型,在整個對象類型中,屬性的名稱必須是唯一的,但是在不同的對象類型之間,屬性的命名是可以重復的。
1.屬性的聲明必須在方法的聲明以前,也就是說在對象規范中create type下面的聲明必須最先是屬性的定義。
2.屬性的數據類型必須是oracle數據庫類型,不能是任何PLSQL類型或PLSQL自定義類型,但是排除了oracle中的rowid,urowid,long,log raw,nchar,nclob,nvarchar2類型。
3.在定義屬性時不能對屬性應用NOT NULL約束或使用default指定默認值。
4.在一個對象類型中至少要定義一個屬性,但是不能大于1000個屬性.
屬性的類型既可以是簡單的數據類型,也可以是對象類型的引用.
定義對象的屬性
create or replace type employee as object(
empno number(4),
ename varchar2(20),
job varchar2(20),
sal number(10,2),
comm number(10,2),
deptno number(4)
)NOT FINAL;
在定義了該對象類型之后,就可以在PLSQL語句塊中通過實例化對象類型,讀取或寫入對象的屬性值了.
declare
v_emp employee_property;
v_sal v_emp.sal%TYPE;
begin
v_emp:=employee_property(7890,'趙五','銷售人員',5000,200,20);
v_sal:=v_emp.sal;
dbms_output.put_line(v_emp.ename||'的薪資是:'|| v_sal);
end;
定義方法
對象方法是在對象規范定義中使用MEMBER或STATIC聲明在對象說明部分的子程序,它們是在屬性聲明之后進行的,
MEMBER方法:成員方法是基于對象實例而不是基于對象類型調用的
STATIC方法:靜態方法獨立于對象實例,也不能在對象類型主體中引用這個對象的屬性
使用MEMBER和STATIC成員方法
create or replace type employee_method as object(
empno number(4),
sal number(10,2),
comm number(10,2),
deptno number(4),
MEMBER procedure change_sal, --實例方法,可以訪問對象本身的屬性
MEMBER function get_sal return number,
--靜態方法,不能訪問對象本身的屬性,只能訪問靜態數據
STATIC procedure change_deptno(p_empno number,p_deptno number),
STATIC function get_sal(p_empno number) return number
)NOT FINAL; --指定該類可以被繼承,如果指定FINAL,表示該類無法被繼承
create or replace type body employee_method
as
MEMBER procedure change_sal
is
begin
self.sal:=self.sal*1.12;
end;
MEMBER function get_sal
return number
is
begin
return sal;
end;
STATIC procedure change_deptno(p_empno number,p_deptno number)
is
begin
update emp set deptno=p_deptno where empno=p_empno;
end;
STATIC function get_sal(p_empno number)
return number
is
v_sal number(10,2);
begin
select sal into v_sal from emp where empno=p_empno;
return v_sal;
end;
end;
MEMBER和STATIC方法使用示例
declare
v_emp employee_method;
begin
v_emp:=employee_method(7999,5000,200,20); --實例化employee_method對象,現在v_emp是對象實例
v_emp.change_sal; --調用對象實例方法,即MEMBER方法
dbms_output.put_line('員工編號為:'||v_emp.empno||'的薪資為:'||v_emp.get_sal);
--下面的代碼調用STATIC方法更新emp表中員工編號為7369的部門編號為20
employee_method.change_deptno(7369,20);
--下面的代碼獲取emp表中員工編號為7369的員工薪資
dbms_output.put_line('員工編號為7369的薪資為:'||employee_method.get_sal(7369));
end;
使用SELF關鍵字
每一個MEMBER類型方法都隱式地聲明了一個內聯參數SELF,它代表了對象類型的一個實例,總是被傳遞給成員方法的第一個參數,實際上的方法體內,也可以不用SELF。
訪問對象類型的屬性
create or replace type employee_salobj as object(
empno number(4),
sal number(10,2),
comm number(10,2),
deptno number(4),
MEMBER procedure change_sal,
MEMBER procedure change_comm,
MEMBER procedure change_deptno,
MEMBER function get_sal return number,
MEMBER function get_comm return number,
MEMBER function get_deptno return INTEGER
)NOT FINAL;
create or replace type body employee_salobj
as
MEMBER procedure change_sal
is
begin
self.sal:=self.sal*1.12;
end;
MEMBER procedure change_comm
is
begin
comm:=comm * 1.12;
end;
MEMBER procedure change_deptno
is
begin
self.deptno:=20;
end;
MEMBER function get_sal
return number
is
begin
return sal;
end;
MEMBER function get_comm
return self.comm;
end;
MEMBER function get_deptno
return integer
is
begin
return self.deptno
end;
end;
在employee_salobj對象類型體的成員實現中,顯式地使用self進行對象屬性的訪問,當沒有顯式使用self關鍵字時,實際上也是隱式地使用了這個關鍵字。
由于STATIC屬于靜態方法級別,因此它不能接受或引用self關鍵字
定義構造函數
當定義了一個對象類型之后,系統會提供一個接收與每個屬性相對應的參數的構造函數。
一般出于如下目的來自定義構造函數:
1.為對象提供初始化功能,以避免許多具有特別用途的過程只初始化對象的不同部分,可以通過構造函數進行統一初始化
2.可以在構造函數中為某些屬性提供默認值,這樣就能確保屬性值的正確性,而不必依賴于調用者所提供的每一個屬性值。
3.出于維護性的思考,在新的屬性添加到對象中時,避免要更改調用構造函數的應用程序中的代碼,這樣可以使已經存在的構造函數調用繼續工作.
構造函數的定義是一個與對象類型名稱具有相同名稱的函數,用于初始化對象,并能返回一個對象類型的新實例。在自定義構造函數時,要么就覆蓋由oracle為每一個對象生成的默認構造函數,要么就定義一個有著不同方法簽名的新構造函數。自定義構造函數使用constructor關鍵字進行聲明.
自定義構造函數示例
create or replace type salary_obj as object(
percent number(10,4), --定義對象類型
sal number(10,2),
--自定義構造函數
constructor function salary_obj(p_sal number) return self as result)
instantiable
final;
/
--定義對象類型體
create or replace type body salary_obj
as
--實現重載的構造函數
constructor function salary_obj(p_sal number)
return self as result
as
begin
self.sal:=p_sal;
self.percent:=1.12;
return;
end;
end;
/
調用
declare
v_salobj1 salary_obj;
v_salobj2 salary_obj;
begin
v_salobj1:=salary_obj(1.12,3000); --使用默認構造函數
v_salobj2:=salary_obj(2000); --使用自定義構造函數
end;
定義MAP和ORDER方法
MAP方法:該函數會將對象實例根據一定的調用規則返回FATE,NUMBER,varchar2類型的標量類型,在映射對象類型為標量函數后,就可以通過對標量函數的比較來得到結果了。
ORDER方法:order方法只能對兩個對象之間進行比較,必須是返回數值型結果的函數,根據結果返回正數,負數或零。該方法只有兩個參數,SELF和另外一個要比較的對象類型,如果傳遞該參數為NULL,則返回NULL。
由于MAP方法一次調用時就將所有的對象映射為一個標量值,因此通常用在排序或合并很多對象時。而order方法一次僅能比較兩個對象,因此在比較多個對象時需要被重復調用,效率會低一些。
定義MAP函數示例
create or replace type employee_map as object(
empno number(4),
sal number(10,2),
comm number(10,2),
deptno number(4),
MAP MEMBER FUNCTION convert return real --定義一個MAP方法
)NOT FINAL;
create or replace type body employee_emp as
MAP MEMBER FUNCTION convert return real is --定義一個MAP方法
begin
return sal+comm;
end;
end;
在定義了MAP函數后,PLSQL會隱式地通過調用MAP函數在多個對象間進行排序或比較。例如下面創建了一個emp_map_tab的對象表,向這個對象表插入多個對象,然后就可以對這個對象表進行對象的排序
create table emp_map_tab of employee_map;
insert into emp_map_tab values(7123,3000,200,20);
col val format a60;
select value(r) val,r.sal+r.comm from emp_emp_tab r order by 1;
定義order函數示例
create or replace type employee_order as object(
empno number(4),
sal number(10,2),
comm number(10,2),
deptno number(4),
ORDER MEMBER FUNCTION match(r employee_order) return integer --定義一個ORDER方法
)NOT FINAL;
create or replace type body employee_order as
ORDER MEMBER FUNCTION match(r employee_order) return integer is
begin
if ((SELF.sal+SELF.comm)<(r.sal+r.comm)) then
return -1;
elsif((SELF.sal+SELF.comm)>(r.sal+r.comm)) then
return 1;
else
return 0;
end if;
end match;
end;
定義了order函數后,就可以對兩個對象進行比較。
declare
emp1 employee_order:=employee_order(7112,3000,200,20);
emp2 employee_order:=employee_order(7113,3800,100,20);
begin
if emp1>emp2 then
dbms_output.put_line('員工1的薪資加提成比員工2大');
elsif emp1<emp2 then
dbms_output.put_line('員工1的薪資加提成比員工2小');
else
dbms_output.put_line('員工1的薪資加提成與員工2相等');
end if;
end;
使用對象類型
對象類型一旦被創建成功,就被保存到了oracle數據字典中,用戶可以再任何的PLSQL塊,子程序或包中使用它來聲明對象
1.聲明對象
聲明的對象必須是已經在oracle數據字典中存在的對象類型。在聲明時可以直接使用對象的構造函數進行初始化,如果沒有初始化,那么對象實例初始化為NULL。
declare
o_emp employee_order;
begin
o_emp:=employee_order(7123,3000,200,20);
dbms_output.put_line('員工編號為:'
||o_emp.empno
||'的薪資和提成為:'
||(o_emp.sal+o_emp.comm)
);
end;
在語句塊的定義區定義了對象類型的變量,o_emp在定義區的初始化狀態下為NULL,在語句塊的執行部分,使用對象類型的構造函數實例化了對象類型,然后通過訪問對象類型的屬性來獲取對象實例的信息.
也可以將對象類型作為存儲過程和存儲函數的形式參數,將對象實例從一個子程序傳遞到另一個子程序。
在子程序中使用對象類型
create or replace procedure changesalary(p_emp in employee_order)
as
begin
if p_emp is not null then --如果對象類型已經實例化,更新emp表
update emp set sal=p_emp.sal,comm=p_emp.comm where empno=p_emp.empno;
end if;
end changesalary;
--使用對象類型作為函數的傳出參數
create or replace function getsalary(p_emp in out employee_order) return number
as
begin
if p_emp is not null then --如果沒有實例化,那就實例化對象類型
p_emp:=employee_order(7125,5000,800,20);
end if;
return p_emp.sal+p_emp.comm;
end;
2.初始化對象
declare
o_emp employee_order:=employee_order(NULL,NULL,NULL,NULL);
begin
o_emp.empno:=7301;
o_emp.sal:=5000;
o_emp.comm:=300;
o_emp.deptno:=20;
end;
3.調用對象方法
在對象類型中,方法分為靜態方法和實例方法,靜態方法在定義時使用STATIC前綴,實例方法在定義時使用MEMBER關鍵字進行定義。這兩類方法的調用方式也不同,實例方法在實例級別進行調用,而靜態方法在對象類型的級別,也就是類級別進行調用。在一些高級程序設計語言比如JAVA,靜態方法又稱為類方法。
調用靜態方法與實例方法實例
create or replace type employee_method as object(
empno number(4),
sal number(10,2),
comm number(10,2),
deptno number(4),
MEMBER PROCEDURE change_sal,
MEMBER FUNCTION get_sal return number,
STATIC PROCEDURE change_deptno(empno number,deptno number),
STATIC FUNCTION get_sal(empno number) return number
)not final;
調用
declare
o_emp employee_method:=employee_method(7369,5000,800,20);
v_sal number(10,2);
begin
v_sal:=o_emp.get_sal; --調用對象實例級別的方法
dbms_output.put_line('對象實例級別的工資為:'||v_sal);
v_sal:=employee_method.get_sal(o_emp.empno); --調用對象級別的方法
dbms_output.put_line('對象類型級別的工資為:'||v_sal);
end;
使用嵌套對象類型
嵌套對象類型是指一個對象中嵌入另一個對象類型。在為對象類型定義屬性時,除了可以使用標量類型之外,還可以通過自定義的對象類型來提升整個對象類型的靈活性。
定義地址對象類型
create or replace type address_type
as object
(street_addr1 varchar2(25),
street_addr2 varchar2(25),
city varchar2(30),
state varchar2(2),
zip_code number,
--成員方法,返回地址字符串
MEMBER FUNCTION tostring return varchar2,
--MAP方法提供地址比較函數
MAP MEMBER FUNCTION mapping_function return varchar2
)
--定義地址對象類型體,實現成員方法與MAP函數
create or replace type body address_type
as
MEMBER FUNCTION tostring
return varchar2
is
begin
if (street_addr2 is not null)
then
return street_addr1
||CHR(10)
||street_addr2
||CHR(10)
||city
||','
||state
||' '
||zip_code;
else
return street_addr1 ||CHR(10)||city||','||state||' '||zip_code;
end if;
end;
MAP MEMBER FUNCTION mapping_function
return varchar2
is
begin
return to_char(NVL(zip_code,0),'fm00000')
||LPAD (NVL(city,''),30)
||LPAD (NVL(street_addr1,''),25)
||LPAD (NVL(street_addr2,''),25);
end;
end;
定義包含其他對象類型的類型
create or replace type employee_addr as object(
empno number(4),
sal number(10,2),
comm number(10,2),
deptno number(4),
addr address_type,
MEMBER FUNCTION get_emp_info return varchar2
)NOT FINAL;
--定義對象類型體,實現get_emp_info方法
create or replace type body employee_addr
as
MEMBER FUNCTION get_emp_info
return varchar2
is
begin
return '員工'||SELF.empno||'的地址為:'||SELF.addr.tostring;
end;
end;
為了使用employee_addr對象類型,在構造對象的實例時,必須要同時構造address_type的嵌套對象類型。
declare
o_address address_type;
o_emp employee_addr;
begin
--實例化地址對象類型
o_address:=address_type('玉蘭一街','二巷','深圳','DG',523343);
--實例化員工對象類型
o_emp:=employee_addr(7369,5000,800,20,o_address);
--輸出員工信息
dbms_output.put_line('員工信息為'||o_emp.get_emp_info);
end;
對象繼承
繼承是指在已存在的對象類型的基礎上建立新對象類型的一種技術,新定義的類可包含現有類所聲明的數據,定義及包含新定義的對象類型所增加的聲明的組合。
對象類型繼承由父類型和子類型組成,其中父類型用于定義可供子類型使用的公共的屬性和方法,而子類型不但可以使用這些公共的屬性和方法,還可以具有自己私有的屬性和方法。
例如,在對現實世界的實體進行抽象時,可以發現企業中的員工都有一些共性,因此將其抽象出一個父類型,用來定義一個基類,比如員工都包含了姓名,性別,出生日期等,可以基于這些特性定義一個person_obj的對象類型,然后在該類型的基礎上繼承一個子類employee_personobj類型,除了具有person_obj的特性外,還具有員工證件號碼,工資,提成和職位信息,類繼承結構。
實現person_obj父對象
create or replace type person_obj as object(
person_name varchar(20),
gender varchar2(2),
birthdate DATE,
address varchar2(50),
MEMBER FUNCTION get_info return varchar2
)NOT FINAL;
create or replace type body person_obj
as
MEMBER FUNCTION get_info return varchar2
is
begin
return '姓名:' || person_name||',家庭住址:'||address;
end;
end;
子對象employee_personpbj的實現
create or replace type employee_personobj under person_obj(
empno number(6),
sal number(10,2),
job varchar2(10),
MEMBER FUNCTION get_emp_info return varchar2
);
create or replace type body employee_personobj as
MEMBER FUNCTION get_emp_info return varchar2 is
begin
return '員工編號:' || SELF.empno ||'員工名稱:' || SELF.person_name||'職位:'||SELF.job;
end;
end;
為了從一個父對象中繼承,在子對象中使用UNDER關鍵字,指定一個父對象名稱,該父對象必須使用NOT FINAL關鍵字定義的對象。在子對象中新增了屬性和方法后,就被合并到父對象中去了,因此可以看到在對象體實現時,可以直接使用SELF關鍵字訪問父對象中的person_name屬性。
使用方法:
declare
o_emp employee_personobj;
begin
--使用構造函數實例化員工對象
o_emp:=employee_personobj('張小五','F',TO_DATE('1983-01-01','YYYY-MM-DD'),'中信',7981,5000,'Programmer');
dbms_output.put_line(o_emp.get_info);
dbms_output.put_line(o_emp.get_emp_info);
end;
方法重載
所謂重載就是定義一個或多個具有同名的函數或過程,但是參數類型名個數不同,由編譯器根據調用參數確定執行哪一個子程序。這種重載方式有時候也稱為靜態多態。在使用對象繼承時,也可以使用方法重載。但是這種方法重載不同于過程或包中的重載,這種重載使用了動態方法調用的能力,也稱為動態多態或運行時多態。也就是說具體的調用方法不是在編譯時確定的,而是在代碼實際執行時才確定的重載。
對象方法的重載使用OVERRIDING關鍵字,不是根據參數的個數來決定調用哪一個方法,而是根據優先級進行調用,也就是總是先調用子類的方法。
實現對象方法重載
create or replace type employee_personobj under person_obj(
empno number(6),
sal number(10,2),
job varchar2(10),
MEMBER FUNCTION get_emp_info return varchar2,
--定義重載方法
OVERRIDING MEMBER FUNCTION get_info return varchar2
);
create or replace type body employee_personobj as
MEMBER FUNCTION get_emp_info return varchar2 is
begin
return '員工編號:' || SELF.empno||'員工名稱:'||SELF.person_name||'職位:'||SELF.job;
end;
--實現重載方法
OVERRIDING MEMBER FUNCTION get_info return varchar2 as
begin
return '員工編號:' ||SELF.empno||'員工名稱:'||SELF.person_name||'職位':||SELF.job;
end;
end;
調用employee_personobj對象實例的get_info方法時,將看到的是來自重載方法中的消息
declare
o_emp employee_personobj;
begin
--使用構造函數實例化員工對象
o_emp:=employee_personobj('張小五','F',TO_DATE('1983-01-01','YYYY-MM-DD'),'中信',7981,5000,'Programmer');
dbms_output.put_line(o_emp.get_info);
end;
管理對象表
對象表就像普通的表一樣,只是存儲的事對象類型,該表中的每一個字段與對象的一個屬性相對應,然后使用對象表的每一行或者稱為每一條記錄存儲一個對象類型的實例。
create table emp_obj_table of employee_personobj;
創建對象表使用的是create table of 語句。
可以使用desc 查看到結構,和對象中包含的屬性類型。
創建的對象表一旦引用了特定的對象類型,就不能使用drop type語句對對象類型進行刪除,如果非要這樣做,oracle會報錯。
如果對象類型中包含嵌套的對象類型,那么嵌套的對象表類型會被作為一列存儲到對象表中,比如employee_addr的addr屬性是一個嵌套了address_type對象類型的屬性,因此當創建一個employee_addr對象類型的數據表,會將addr作為一個單獨的列。
create table emp_addr_table of employee_addr;
使用set desc depth all linenum on 語句。
插入對象表
插入數據的語法與向普通表插入數據一樣,使用insert命令。
除了直接插入列值外,在向對象類型的表中插入數據時,可以先實例化一個對象類型,然后向insert語句的values子句傳入構建的對象類型。
declare
o_emp employee_personobj;
begin
--使用構造函數實例化員工對象
o_emp:=employee_personobj('張小五','F',TO_DATE('1983-01-01','YYYY-MM-DD'),'中信',7981,5000,'Programmer');
insert into emp_obj_table values(o_emp);
end;
檢索對象表
對象表的查詢與關系表的查詢一樣。
1.value函數
在查詢語句中使用value函數將返回存儲在對象表中的對象實例,因此對于查詢的單行記錄,可以使用select into 語句將查詢出來的值插入到預定義的對象實例中;對于查詢返回的多行記錄,可以使用游標來獲取查詢出來的對象實例。
select value(e) from emp_obj_table e;
該查詢返回了存儲在emp_obj_table表中所有的對象實例,每一行一個對象實例。
下面演示使用select into 將查詢的結果賦值給一個對象類型的變量:
declare
o_emp employee_personobj;
begin
--使用select into 語句將value函數返回的對象實例插入到對象類型的變量
select value(e) into o_emp from emp_obj_table e where e.person_name='張小五';
--輸出對象類型的屬性值
dbms_output.put_line(o_emp.person_name||'的職位是:'||o_emp.job);
end;
使用游標和value函數查詢多行數據結果
declare
o_emp employee_personobj;
cursor all_emp
is
select value(e) as emp from emp_obj_table e;
begin
for each_emp in all_emp
loop
o_emp:=each_emp.emp;
--輸出對象實例信息
dbms_output.put_line(o_emp.person_name||'的職位是:'||o_emp.job);
end loop;
end;
2.REF函數
與value相對應的ref函數也可以用來檢索對象表中的數據,但是由其名可知,它返回的事一個對象的引用。二者之間的主要區別在于引用類型返回的只是指向對象實際位置的一個指針,而value類型會把對象副本從一個子程序傳遞到另一個子程序,程序執行時的效率可能會降低。
使用共享對象類型,可以避免數據不必要的重復,而且在共享的內容更新時,任何引用所指向的內容也會被立即更新。
create type address as object( --創建地址類型
street varchar2(35),
city varchar2(15),
state char(2),
zip_code integer
);
create table addresses of address; --創建地址對象表
create type person as object( --創建人員對象類型
person_name varchar2(15),
birthday DATE,
home_address REF address, --使用ref關鍵字,指定屬性為指向另一個對象表的對象
phone_number varchar2(15)
);
create table persons of person; --創建人員對象表
插入數據
insert into addresses values(address ('玉蘭','深圳','GD','321413'));
insert into persons values(person ('王小五',TO_DATE('1983-01-01','YYYY-MM-DD'),(select ref(a) from addresses a where street='玉蘭'),'1312332'));
使用PL/SQL語句塊向對象表中插入引用類型的對象
declare
addref ref address; --定義一個引用類型的對象
begin
select ref (a) into addref from addresses a where street='玉蘭';
insert into persons values(person('武大郎',TO_DATE('1983-01-01','YYYY-MM-DD'),addref,'1312312'));
end;
在語句塊中使用ref關鍵字定義了一個指向address對象類型的引用類型,然后使用ref函數從address表中返回匹配的引用類型的指針,最后將這個引用類型作為home_address屬性的值插入到persons表中.
當對象表中包含引用類型時,如果直接使用select語句進行查詢,引用類型的列是一串數字碼,而且引用類型的對象無法直接訪問其屬性。
select person_name,home_address from persons;
如果使用了deref函數,則可以查詢到引用類型所指向的地址類型的值。
select person_name,deref (home_address) as home from persons;
在PL/SQL語句中使用ref類型的變量時,不能直接訪問對象的屬性,必須首先通過deref函數解除引用后,才能使用對象類型的屬性.
更新對象表
更新對象表時既可以把對象表看作是一個普通的關系型表,與關系表一樣把對象表中的每個屬性作為一列調用作為一列調用update語句,也可以將一行看作是一個對象,在update語句中對對象進行賦值。
update emp_obj_table empobj set empobj.gender='M' where empobj.person_name='張小五';
另一種方法是直接更新一個對象表中的對象實例,因此需要先實例化一個對象實例。
update emp_obj_table empobj set empobj=employee_personobj('李曉琪','F',TO_DATE('1983-01-01','YYYY-MM-DD'),'眾泰',7981,7000,'Testing') where person_name='張小五';
在操縱對象表時,還可以在where子句中把一行看作一個對象,可以使用對象標識符來唯一標識要更改的對象,對象標識符是對象表中為了唯一標識一條記錄而定義的一串數字值,對于一個對象來說,需要使用REF函數來獲取對象的標識符,在where語句中使用對象類型進行檢索的示例
在where子句中使用對象類型
declare
emp_ref ref employee_personobj; --定義引用對象類型
begin --從對象表中獲取對劉小燕的對象引用
select ref(e1) into emp_ref from emp_obj table e1 where person_name='劉小燕';
update emp_obj_table emp_obj set emp_obj=employee_personobj('何曉峰','F',TO_DATE('1985-08- 01','YYYY-MM-DD'),'本田',7981,7000,'developer') where ref (emp_obj)=emp_ref;
end;
如果對象表的屬性列表中包含了引用類型,也就是說包含了指向行對象數據的指針,如果要修改其列所引用的數據,就必須修改相應的行對象。例如在persons表中,home_address字段是一個指向address對象類型的引用,因此如果要update這個包含引用類型的表。
declare
addr address;
begin
select deref(home_address) into addr from persons where person_name='張小五';
addr.street:='五一';
update address set street=addr.street where zip_code='21312';
end;
先使用deref函數返回指針所指向的address對象實例的引用,然后將更改的信息更新回address表中就完成了對引用記錄的更改。
刪除對象表
與刪除普通表類似,對象表的刪除使用delete語句,下面的語句像刪除普通的關系表一樣刪除emp_obj_table表中員工名稱為張小五的記錄
delete from emp_obj_table where person_name='張小五';
與update類似,還可以在where子句中使用引用類型的對象進行刪除。例如要刪除emp_obj_table表中員工名稱為劉小燕的記錄。
declare
emp_ref ref employee_personobj;
begin
select ref (e1) into emp_ref from emp_obj_table e1 where person_name='劉小燕'; --從對象表中獲取對劉小燕的對象引用
delete from emp_obj_table emp_obj where ref (emp_obj)=emp_ref
end; --使用delete語句刪除emp_obj_table表中劉小燕的記錄
通過使用ref函數,將員工名稱為劉小燕的記錄進行了正確的刪除。
創建對象列
除了將整個對象作為表中的列來存儲的對象表之外,還可以為關系表中的某一列的屬性指定為對象類型,這種表稱為帶對象列的關系表。這種帶對象類型的關系表與對象表的主要不同在于對象表時通過使用對象標識符來引用對象實例的,而對于列對象來說是沒有oracle對象標識符的,列對象的對象實例屬于關系型數據庫中的記錄,具有一個rowid值作為標識符。
定義dept_obj對象類型
create or replace type dept_obj as object(
deptno number(10),
dname varchar2(30),
loc varchar2(30),
MEMBER FUNCTION get_dept_info return varchar2
) INSTANTIABLE NOT FINAL;
定義對象類型體
create or replace type body dept_obj as
MEMBER FUNCTION get_dept_info return varchar2 is
begin
return '部門編號:' || SELF.deptno ||'部門名稱:'||SELF.dname||'職位:'||SELF.loc;
end;
end;
對象類型dept_obj封裝了部門信息,可以看到具有部門編號,部門名稱和部門的地址信息,接下來創建一個名為emp_colobj的表,該表用來存放員工信息,但是在部門列中,將使用dept_obj對象類型作為列類型,可以再表中存儲關于部門的詳細信息。
create table emp_colobj(
empno number(10) NOT NULL primary key,
ename varchar2(30),
job varchar2(30),
sal number(10,2),
deptcol dept_obj
) --dept列指定為dept_obj對象類型
在對象表中綁定了某個對象類型后,不能直接對對象表中的列及類型進行操作,比如新增列或對列進行修改等,但是關系表中包含對象列類型則沒有這個限制,可以使用標準的ALTER TABLE語句來進行操作.
使用對象視圖
為了創建一個對象視圖,必須首先創建一個與底層的數據表的列具有相匹配屬性的對象類型。
定義emp_tbl_obj對象類型
create or replace type emp_tbl_obj as object(
empno number(6),
ename varchar2(10),
job varchar2(18),
mgr number(4),
hiredate DATE,
sal number(7,2),
comm number(7,2),
deptno number(2),
MEMBER FUNCTION get_emp_info return varchar2
)INSTANTIABLE NOT FINAL;
create or replace type body emp_tbl_obj as
MEMBER FUNCTION get_emp_info return varchar2 is
begin
return '員工編號:' ||SELF.empno||'員工名稱:'||SELF.ename||'職位:'||SELF.job;
end;
end;
在創建對象視圖時,必須要確定要使用的OID(對象標識符).對象標識符是用來唯一標識一行對象的一個字符串,通過OID可以保證對對象實例引用的唯一性。OID標識符僅在對象表和對象視圖上被創建,一旦一個OID被賦給了一個對象,那么將永遠屬于那個對象。通常情況下,oracle會自動產生OID值,不需要要手工干預,但是在定義對象視圖時,可以覆蓋系統產生OID的機制,更改為使用對象表的主鍵來替代.
create view view_name of object_name
with object identifier(primary_key)
as
sql_statement;
view_name指定對象視圖的名稱,object_name用于指定對象視圖的對象名稱,with object identifier用于指定OID方式,可以指定表的主鍵作為OID,sql_statement是對關系表的sql查詢語句時。
create view emp_view
of emp_tb1_obj
with object identifier(empno)
as
select e.empno,e.ename,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno from emp e;
使用對象類型的視圖
declare
o_emp emp_tb1_obj;
begin
--查詢對象類型
select value(e) into o_emp from emp_view e where empno=7369;
--輸出對象類型的屬性
dbms_output.put_line('員工'||o_emp.ename||'的薪資為:'||o_emp.sal);
dbms_output.put_line(o_emp.get_emp_info); --調用對象類型的成員方法
end;
管理對象類型
1.查看對象類型
COL type_name format A20;
select type_name,attributes,final,typecode from user_types where type_name like 'EMP%' and typecode='OBJECT';
通過使用select connect by語句,還可以根據type_name和supertype_name來查詢對象的繼承結構.
set pagesize 500;
select rpad (' ',3 * (LEVEL-1)) |from user_types where typecode='OBJECT' CONNECT BY PRIOR type_name=superty
2.修改對象類型
如果已經基于對象類型建立了其他的對象類型或對象表,那么在為對象類型增加或刪除屬性時,必須要使用cascade關鍵字.
--添加mgr屬性
alter type employee_personobj add attribute mgr number(6) cascade;
--刪除sal屬性
alter type employee_personobj drop attribute sal cascade;
修改對象類型的成員方法
alter type employee_personobj drop member function get_emp_info return varchar2 cascade;
--新增一個get_employee的成員方法
alter type employee_personobj add member function get_employee return varchar2 cascade;
--更改對象類型體,以便增加在對象類型規范中定義的方法
create or replace type body employee_personobj as
member function get_employee return varchar2 is
begin
return '員工編號:' ||SELF.empno||'員工名稱:'||SELF.person_name||'職位:'||SELF.job;
end;
end;
如果從基類刪除一個方法,那么也必須修改覆蓋被刪除方法的子類,可以用alter type 的casade選擇來判斷是否有子類被影響到:如果有子類覆蓋了方法,那么語句被回滾。為了能成功地從基類刪除一個方法。
1.先從子類刪除方法
2.從基類刪除方法,然后用不帶overriding關鍵字的alter type把它重新添加進去.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。