溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PLSQL面向?qū)ο缶幊?/h1>
發(fā)布時間:2020-07-09 02:31:56 來源:網(wǎng)絡(luò) 閱讀:2351 作者:潘闊 欄目:關(guān)系型數(shù)據(jù)庫

面向?qū)ο缶幊毯喎QOOP編程,實(shí)際上是對現(xiàn)實(shí)世界事物的一種抽象的過程。它的核心是把對象的定義和實(shí)現(xiàn)進(jìn)行區(qū)分,讓定義部分對象所具有的結(jié)構(gòu),讓實(shí)現(xiàn)部分根據(jù)定義部分定義的具體結(jié)構(gòu)進(jìn)行具體的實(shí)現(xiàn)。


用于生產(chǎn)玩具的模具叫做類,通常設(shè)計(jì)類的過程也可以稱為建模,當(dāng)然這個模不是模具的模,而是對類的模型進(jìn)行建模。所生產(chǎn)的玩具可以叫做對象,類是對象的抽象,而對象是類的具體實(shí)例。類是抽象的,不占用內(nèi)存,而對象是具體的,占用存儲空間。類是用于創(chuàng)建對象的藍(lán)圖,它是一個定義包括在特定類型的對象中的方法和變量的軟件模版。


對類的定義是一組具有相同數(shù)據(jù)結(jié)構(gòu)和相同操作的對象的集合,類的定義包括一組代表其特性的屬性。以及一組表示其執(zhí)行行為的方法,類定義可以看作是一個具有相似特性與共同行為的對象模版,可以用來產(chǎn)生對象,而每個對象都是類的實(shí)例,都可以使用類中提供的方法,對象的具體狀態(tài)包含在對象實(shí)例變量中。


封裝:也叫做信息封裝,確保對象不會以不可預(yù)期的方式改變其他對象的內(nèi)部狀態(tài)。只有在那些提供了內(nèi)部狀態(tài)改變方法的對象中,才可以訪問其他內(nèi)部狀態(tài)。每類對象都提供一個與其他對象聯(lián)系的接口,并規(guī)定了其他對象進(jìn)行調(diào)用的方法


多態(tài)性:對象的引用和類會涉及其他許多不同類型的對象,而且引用對象所產(chǎn)生的結(jié)果將依據(jù)實(shí)際調(diào)用的類型


繼承性:允許在現(xiàn)存的對象基礎(chǔ)上創(chuàng)建子類對象,統(tǒng)一并增強(qiáng)了多態(tài)性和封裝性。典型地來說就是用類來對對象進(jìn)行分組,而且還可以定義新類為現(xiàn)存的類的擴(kuò)展,這樣就可以將類組織成樹型或網(wǎng)狀結(jié)構(gòu),這體現(xiàn)了對象的通用性。


對象類型實(shí)際上就是在上一小節(jié)中介紹的類型,類的實(shí)例就是對象。對象的類型封裝了數(shù)據(jù)結(jié)構(gòu)和用于操縱這些數(shù)據(jù)結(jié)構(gòu)的過程和函數(shù),這使得通過定義對象類型就可以封裝一些較復(fù)雜的代碼,提高應(yīng)用開發(fā)的效率和速度??梢栽谝粋€對象類型說明部分聲明屬性和方法,屬性不能是常數(shù),異常,游標(biāo)或類型,最大的屬性聲明數(shù)量是1000個,但是必須至少聲明一個屬性,而方法是可選的。屬性描述了對象的特性,方法則是對象類型具有的功能。在PLSQL中,方法就是一些子程序,可以是函數(shù),也可以是過程,方法名稱不能和它的對象類型名稱和屬性名稱一樣,方法在實(shí)例級別或?qū)ο箢愋图墑e被調(diào)用。



PLSQL中對象的組成結(jié)構(gòu)


PLSQL中的對象類型是一種自定義的符合類型,它的定義與包的定義非常相似

對象類型規(guī)范:是對象與應(yīng)用的接口,它用于定義對象的公用屬性和方法

對象類型體:用于實(shí)現(xiàn)對象類型規(guī)范所定義的公用方法.


例如在定義員工對象類型時,先在對象類型規(guī)范中定義好了對象的所有屬性,以及對象可被調(diào)用的方法聲明,這些方法并沒有具體的實(shí)現(xiàn)部分,僅可供外部調(diào)用的方法簽名。而具體的方法體代碼實(shí)現(xiàn)則定義在對象類型體中。


在定義對象類型的屬性時,不能指定對象屬性的默認(rèn)值,也不能指定NOT NULL選項(xiàng)。


PLSQL中可以定義的幾種類型的方法

1.構(gòu)造方法:該方法類似于JAVA等語言中的構(gòu)造函數(shù),用來初始化一個對象類型并返回對象的實(shí)例

2.MEMBER方法:該方法允許對象的實(shí)例進(jìn)行調(diào)用,在MEMBER方法中可以訪問對象實(shí)例的數(shù)據(jù),通常稱為實(shí)例方法或成員方法

3.STATIC方法:該方法可以直接在對象類型上進(jìn)行調(diào)用,它用于在對象類型上執(zhí)行全局操作,通常稱為靜態(tài)方法

4.MAP方法:用于在多個對象間排序的映射方法。

5.ORDER方法:用于在兩個對象實(shí)例間排序的排序方法。



定義對象類型

對象類型包含對象類型規(guī)范和對象類型體兩大部分,因此在定義時必須先定義對象類型規(guī)范,然后再定義對象類型體.


定義employee_obj對象規(guī)范

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;



定義屬性

屬性是對象類型特性的定義,屬性聲明是一個對象必需的,也就是說一個對象類型至少要定義一個屬性。屬性的定義與變量的定義相似,也具有名稱和數(shù)據(jù)類型,在整個對象類型中,屬性的名稱必須是唯一的,但是在不同的對象類型之間,屬性的命名是可以重復(fù)的。


1.屬性的聲明必須在方法的聲明以前,也就是說在對象規(guī)范中create type下面的聲明必須最先是屬性的定義。

2.屬性的數(shù)據(jù)類型必須是oracle數(shù)據(jù)庫類型,不能是任何PLSQL類型或PLSQL自定義類型,但是排除了oracle中的rowid,urowid,long,log raw,nchar,nclob,nvarchar2類型。

3.在定義屬性時不能對屬性應(yīng)用NOT NULL約束或使用default指定默認(rèn)值。

4.在一個對象類型中至少要定義一個屬性,但是不能大于1000個屬性.

屬性的類型既可以是簡單的數(shù)據(jù)類型,也可以是對象類型的引用.


定義對象的屬性

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語句塊中通過實(shí)例化對象類型,讀取或?qū)懭雽ο蟮膶傩灾盗?

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;




定義方法

對象方法是在對象規(guī)范定義中使用MEMBER或STATIC聲明在對象說明部分的子程序,它們是在屬性聲明之后進(jìn)行的,

MEMBER方法:成員方法是基于對象實(shí)例而不是基于對象類型調(diào)用的

STATIC方法:靜態(tài)方法獨(dú)立于對象實(shí)例,也不能在對象類型主體中引用這個對象的屬性


使用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, --實(shí)例方法,可以訪問對象本身的屬性

MEMBER function get_sal return number,

--靜態(tài)方法,不能訪問對象本身的屬性,只能訪問靜態(tài)數(shù)據(jù)

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); --實(shí)例化employee_method對象,現(xiàn)在v_emp是對象實(shí)例

v_emp.change_sal; --調(diào)用對象實(shí)例方法,即MEMBER方法

dbms_output.put_line('員工編號為:'||v_emp.empno||'的薪資為:'||v_emp.get_sal);

--下面的代碼調(diào)用STATIC方法更新emp表中員工編號為7369的部門編號為20

employee_method.change_deptno(7369,20);

--下面的代碼獲取emp表中員工編號為7369的員工薪資

dbms_output.put_line('員工編號為7369的薪資為:'||employee_method.get_sal(7369));

end;



使用SELF關(guān)鍵字

每一個MEMBER類型方法都隱式地聲明了一個內(nèi)聯(lián)參數(shù)SELF,它代表了對象類型的一個實(shí)例,總是被傳遞給成員方法的第一個參數(shù),實(shí)際上的方法體內(nèi),也可以不用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對象類型體的成員實(shí)現(xiàn)中,顯式地使用self進(jìn)行對象屬性的訪問,當(dāng)沒有顯式使用self關(guān)鍵字時,實(shí)際上也是隱式地使用了這個關(guān)鍵字。

由于STATIC屬于靜態(tài)方法級別,因此它不能接受或引用self關(guān)鍵字



定義構(gòu)造函數(shù)


當(dāng)定義了一個對象類型之后,系統(tǒng)會提供一個接收與每個屬性相對應(yīng)的參數(shù)的構(gòu)造函數(shù)。

一般出于如下目的來自定義構(gòu)造函數(shù):

1.為對象提供初始化功能,以避免許多具有特別用途的過程只初始化對象的不同部分,可以通過構(gòu)造函數(shù)進(jìn)行統(tǒng)一初始化

2.可以在構(gòu)造函數(shù)中為某些屬性提供默認(rèn)值,這樣就能確保屬性值的正確性,而不必依賴于調(diào)用者所提供的每一個屬性值。

3.出于維護(hù)性的思考,在新的屬性添加到對象中時,避免要更改調(diào)用構(gòu)造函數(shù)的應(yīng)用程序中的代碼,這樣可以使已經(jīng)存在的構(gòu)造函數(shù)調(diào)用繼續(xù)工作.


構(gòu)造函數(shù)的定義是一個與對象類型名稱具有相同名稱的函數(shù),用于初始化對象,并能返回一個對象類型的新實(shí)例。在自定義構(gòu)造函數(shù)時,要么就覆蓋由oracle為每一個對象生成的默認(rèn)構(gòu)造函數(shù),要么就定義一個有著不同方法簽名的新構(gòu)造函數(shù)。自定義構(gòu)造函數(shù)使用constructor關(guān)鍵字進(jìn)行聲明.


自定義構(gòu)造函數(shù)示例

create or replace type salary_obj as object(

percent number(10,4),  --定義對象類型

sal number(10,2),

--自定義構(gòu)造函數(shù)

constructor function salary_obj(p_sal number) return self as result)

instantiable

final;

/


--定義對象類型體

create or replace type body salary_obj

as

--實(shí)現(xiàn)重載的構(gòu)造函數(shù)

constructor function salary_obj(p_sal number)

return self as result

as

begin

self.sal:=p_sal;

self.percent:=1.12;

return;

end;

end;

/


調(diào)用

declare

v_salobj1 salary_obj;

v_salobj2 salary_obj;

begin

v_salobj1:=salary_obj(1.12,3000);   --使用默認(rèn)構(gòu)造函數(shù)

v_salobj2:=salary_obj(2000); --使用自定義構(gòu)造函數(shù)

end;




定義MAP和ORDER方法

MAP方法:該函數(shù)會將對象實(shí)例根據(jù)一定的調(diào)用規(guī)則返回FATE,NUMBER,varchar2類型的標(biāo)量類型,在映射對象類型為標(biāo)量函數(shù)后,就可以通過對標(biāo)量函數(shù)的比較來得到結(jié)果了。

ORDER方法:order方法只能對兩個對象之間進(jìn)行比較,必須是返回?cái)?shù)值型結(jié)果的函數(shù),根據(jù)結(jié)果返回正數(shù),負(fù)數(shù)或零。該方法只有兩個參數(shù),SELF和另外一個要比較的對象類型,如果傳遞該參數(shù)為NULL,則返回NULL。


由于MAP方法一次調(diào)用時就將所有的對象映射為一個標(biāo)量值,因此通常用在排序或合并很多對象時。而order方法一次僅能比較兩個對象,因此在比較多個對象時需要被重復(fù)調(diào)用,效率會低一些。


定義MAP函數(shù)示例

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函數(shù)后,PLSQL會隱式地通過調(diào)用MAP函數(shù)在多個對象間進(jìn)行排序或比較。例如下面創(chuàng)建了一個emp_map_tab的對象表,向這個對象表插入多個對象,然后就可以對這個對象表進(jìn)行對象的排序

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函數(shù)示例

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函數(shù)后,就可以對兩個對象進(jìn)行比較。

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;




使用對象類型


對象類型一旦被創(chuàng)建成功,就被保存到了oracle數(shù)據(jù)字典中,用戶可以再任何的PLSQL塊,子程序或包中使用它來聲明對象

1.聲明對象

聲明的對象必須是已經(jīng)在oracle數(shù)據(jù)字典中存在的對象類型。在聲明時可以直接使用對象的構(gòu)造函數(shù)進(jìn)行初始化,如果沒有初始化,那么對象實(shí)例初始化為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;


在語句塊的定義區(qū)定義了對象類型的變量,o_emp在定義區(qū)的初始化狀態(tài)下為NULL,在語句塊的執(zhí)行部分,使用對象類型的構(gòu)造函數(shù)實(shí)例化了對象類型,然后通過訪問對象類型的屬性來獲取對象實(shí)例的信息.


也可以將對象類型作為存儲過程和存儲函數(shù)的形式參數(shù),將對象實(shí)例從一個子程序傳遞到另一個子程序。


在子程序中使用對象類型

create or replace procedure changesalary(p_emp in employee_order)

as

begin

if p_emp is not null then         --如果對象類型已經(jīng)實(shí)例化,更新emp表

update emp set sal=p_emp.sal,comm=p_emp.comm where empno=p_emp.empno;

end if;

end changesalary;


--使用對象類型作為函數(shù)的傳出參數(shù)

create or replace function getsalary(p_emp in out employee_order) return number

as

begin

if p_emp is not null then          --如果沒有實(shí)例化,那就實(shí)例化對象類型

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.調(diào)用對象方法

在對象類型中,方法分為靜態(tài)方法和實(shí)例方法,靜態(tài)方法在定義時使用STATIC前綴,實(shí)例方法在定義時使用MEMBER關(guān)鍵字進(jìn)行定義。這兩類方法的調(diào)用方式也不同,實(shí)例方法在實(shí)例級別進(jìn)行調(diào)用,而靜態(tài)方法在對象類型的級別,也就是類級別進(jìn)行調(diào)用。在一些高級程序設(shè)計(jì)語言比如JAVA,靜態(tài)方法又稱為類方法。


調(diào)用靜態(tài)方法與實(shí)例方法實(shí)例

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;


調(diào)用

declare

o_emp employee_method:=employee_method(7369,5000,800,20);

v_sal number(10,2);

begin

v_sal:=o_emp.get_sal;           --調(diào)用對象實(shí)例級別的方法

dbms_output.put_line('對象實(shí)例級別的工資為:'||v_sal);

v_sal:=employee_method.get_sal(o_emp.empno);   --調(diào)用對象級別的方法

dbms_output.put_line('對象類型級別的工資為:'||v_sal);

end;


使用嵌套對象類型

嵌套對象類型是指一個對象中嵌入另一個對象類型。在為對象類型定義屬性時,除了可以使用標(biāo)量類型之外,還可以通過自定義的對象類型來提升整個對象類型的靈活性。


定義地址對象類型

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方法提供地址比較函數(shù)

MAP MEMBER FUNCTION mapping_function return varchar2

)


--定義地址對象類型體,實(shí)現(xiàn)成員方法與MAP函數(shù)

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;


--定義對象類型體,實(shí)現(xiàn)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對象類型,在構(gòu)造對象的實(shí)例時,必須要同時構(gòu)造address_type的嵌套對象類型。

declare

o_address address_type;

o_emp employee_addr;

begin

--實(shí)例化地址對象類型

o_address:=address_type('玉蘭一街','二巷','深圳','DG',523343);

--實(shí)例化員工對象類型

o_emp:=employee_addr(7369,5000,800,20,o_address);

--輸出員工信息

dbms_output.put_line('員工信息為'||o_emp.get_emp_info);

end;




對象繼承

繼承是指在已存在的對象類型的基礎(chǔ)上建立新對象類型的一種技術(shù),新定義的類可包含現(xiàn)有類所聲明的數(shù)據(jù),定義及包含新定義的對象類型所增加的聲明的組合。

對象類型繼承由父類型和子類型組成,其中父類型用于定義可供子類型使用的公共的屬性和方法,而子類型不但可以使用這些公共的屬性和方法,還可以具有自己私有的屬性和方法。


例如,在對現(xiàn)實(shí)世界的實(shí)體進(jìn)行抽象時,可以發(fā)現(xiàn)企業(yè)中的員工都有一些共性,因此將其抽象出一個父類型,用來定義一個基類,比如員工都包含了姓名,性別,出生日期等,可以基于這些特性定義一個person_obj的對象類型,然后在該類型的基礎(chǔ)上繼承一個子類employee_personobj類型,除了具有person_obj的特性外,還具有員工證件號碼,工資,提成和職位信息,類繼承結(jié)構(gòu)。



實(shí)現(xiàn)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的實(shí)現(xiàn)

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關(guān)鍵字,指定一個父對象名稱,該父對象必須使用NOT FINAL關(guān)鍵字定義的對象。在子對象中新增了屬性和方法后,就被合并到父對象中去了,因此可以看到在對象體實(shí)現(xiàn)時,可以直接使用SELF關(guān)鍵字訪問父對象中的person_name屬性。


使用方法:

declare

o_emp employee_personobj;

begin

--使用構(gòu)造函數(shù)實(shí)例化員工對象

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;



方法重載

所謂重載就是定義一個或多個具有同名的函數(shù)或過程,但是參數(shù)類型名個數(shù)不同,由編譯器根據(jù)調(diào)用參數(shù)確定執(zhí)行哪一個子程序。這種重載方式有時候也稱為靜態(tài)多態(tài)。在使用對象繼承時,也可以使用方法重載。但是這種方法重載不同于過程或包中的重載,這種重載使用了動態(tài)方法調(diào)用的能力,也稱為動態(tài)多態(tài)或運(yùn)行時多態(tài)。也就是說具體的調(diào)用方法不是在編譯時確定的,而是在代碼實(shí)際執(zhí)行時才確定的重載。

對象方法的重載使用OVERRIDING關(guān)鍵字,不是根據(jù)參數(shù)的個數(shù)來決定調(diào)用哪一個方法,而是根據(jù)優(yōu)先級進(jìn)行調(diào)用,也就是總是先調(diào)用子類的方法。


實(shí)現(xiàn)對象方法重載

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;

--實(shí)現(xiàn)重載方法

OVERRIDING MEMBER FUNCTION get_info return varchar2 as

begin

return '員工編號:' ||SELF.empno||'員工名稱:'||SELF.person_name||'職位':||SELF.job;

end;

end;



調(diào)用employee_personobj對象實(shí)例的get_info方法時,將看到的是來自重載方法中的消息

declare

o_emp employee_personobj;

begin

--使用構(gòu)造函數(shù)實(shí)例化員工對象

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;



管理對象表


對象表就像普通的表一樣,只是存儲的事對象類型,該表中的每一個字段與對象的一個屬性相對應(yīng),然后使用對象表的每一行或者稱為每一條記錄存儲一個對象類型的實(shí)例。

create table emp_obj_table of employee_personobj;


創(chuàng)建對象表使用的是create table  of 語句。

可以使用desc 查看到結(jié)構(gòu),和對象中包含的屬性類型。

創(chuàng)建的對象表一旦引用了特定的對象類型,就不能使用drop type語句對對象類型進(jìn)行刪除,如果非要這樣做,oracle會報(bào)錯。


如果對象類型中包含嵌套的對象類型,那么嵌套的對象表類型會被作為一列存儲到對象表中,比如employee_addr的addr屬性是一個嵌套了address_type對象類型的屬性,因此當(dāng)創(chuàng)建一個employee_addr對象類型的數(shù)據(jù)表,會將addr作為一個單獨(dú)的列。

create table emp_addr_table of employee_addr;

使用set desc depth all linenum on 語句。




插入對象表

插入數(shù)據(jù)的語法與向普通表插入數(shù)據(jù)一樣,使用insert命令。

除了直接插入列值外,在向?qū)ο箢愋偷谋碇胁迦霐?shù)據(jù)時,可以先實(shí)例化一個對象類型,然后向insert語句的values子句傳入構(gòu)建的對象類型。

declare

o_emp employee_personobj;

begin

--使用構(gòu)造函數(shù)實(shí)例化員工對象

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;




檢索對象表

對象表的查詢與關(guān)系表的查詢一樣。


1.value函數(shù)

在查詢語句中使用value函數(shù)將返回存儲在對象表中的對象實(shí)例,因此對于查詢的單行記錄,可以使用select into 語句將查詢出來的值插入到預(yù)定義的對象實(shí)例中;對于查詢返回的多行記錄,可以使用游標(biāo)來獲取查詢出來的對象實(shí)例。


select value(e) from emp_obj_table e;

該查詢返回了存儲在emp_obj_table表中所有的對象實(shí)例,每一行一個對象實(shí)例。

下面演示使用select into 將查詢的結(jié)果賦值給一個對象類型的變量:

declare

o_emp employee_personobj;

begin

--使用select into 語句將value函數(shù)返回的對象實(shí)例插入到對象類型的變量

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;


使用游標(biāo)和value函數(shù)查詢多行數(shù)據(jù)結(jié)果

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;

--輸出對象實(shí)例信息

dbms_output.put_line(o_emp.person_name||'的職位是:'||o_emp.job);

end loop;

end;




2.REF函數(shù)


與value相對應(yīng)的ref函數(shù)也可以用來檢索對象表中的數(shù)據(jù),但是由其名可知,它返回的事一個對象的引用。二者之間的主要區(qū)別在于引用類型返回的只是指向?qū)ο髮?shí)際位置的一個指針,而value類型會把對象副本從一個子程序傳遞到另一個子程序,程序執(zhí)行時的效率可能會降低。


使用共享對象類型,可以避免數(shù)據(jù)不必要的重復(fù),而且在共享的內(nèi)容更新時,任何引用所指向的內(nèi)容也會被立即更新。

create type address as object(      --創(chuàng)建地址類型

street varchar2(35),

city varchar2(15),

state char(2),

zip_code integer

);


create table addresses of address;  --創(chuàng)建地址對象表

create type person as object(       --創(chuàng)建人員對象類型

person_name varchar2(15),

birthday DATE,

home_address REF address, --使用ref關(guān)鍵字,指定屬性為指向另一個對象表的對象

phone_number varchar2(15)

);


create table persons of person;   --創(chuàng)建人員對象表

插入數(shù)據(jù)

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語句塊向?qū)ο蟊碇胁迦胍妙愋偷膶ο?/p>

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關(guān)鍵字定義了一個指向address對象類型的引用類型,然后使用ref函數(shù)從address表中返回匹配的引用類型的指針,最后將這個引用類型作為home_address屬性的值插入到persons表中.

當(dāng)對象表中包含引用類型時,如果直接使用select語句進(jìn)行查詢,引用類型的列是一串?dāng)?shù)字碼,而且引用類型的對象無法直接訪問其屬性。

select person_name,home_address from persons;


如果使用了deref函數(shù),則可以查詢到引用類型所指向的地址類型的值。

select person_name,deref (home_address) as home from persons;

在PL/SQL語句中使用ref類型的變量時,不能直接訪問對象的屬性,必須首先通過deref函數(shù)解除引用后,才能使用對象類型的屬性.



更新對象表

更新對象表時既可以把對象表看作是一個普通的關(guān)系型表,與關(guān)系表一樣把對象表中的每個屬性作為一列調(diào)用作為一列調(diào)用update語句,也可以將一行看作是一個對象,在update語句中對對象進(jìn)行賦值。

update emp_obj_table empobj set empobj.gender='M' where empobj.person_name='張小五';


另一種方法是直接更新一個對象表中的對象實(shí)例,因此需要先實(shí)例化一個對象實(shí)例。

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子句中把一行看作一個對象,可以使用對象標(biāo)識符來唯一標(biāo)識要更改的對象,對象標(biāo)識符是對象表中為了唯一標(biāo)識一條記錄而定義的一串?dāng)?shù)字值,對于一個對象來說,需要使用REF函數(shù)來獲取對象的標(biāo)識符,在where語句中使用對象類型進(jìn)行檢索的示例


在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;


如果對象表的屬性列表中包含了引用類型,也就是說包含了指向行對象數(shù)據(jù)的指針,如果要修改其列所引用的數(shù)據(jù),就必須修改相應(yīng)的行對象。例如在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函數(shù)返回指針?biāo)赶虻腶ddress對象實(shí)例的引用,然后將更改的信息更新回address表中就完成了對引用記錄的更改。




刪除對象表

與刪除普通表類似,對象表的刪除使用delete語句,下面的語句像刪除普通的關(guān)系表一樣刪除emp_obj_table表中員工名稱為張小五的記錄

delete from emp_obj_table where person_name='張小五';


與update類似,還可以在where子句中使用引用類型的對象進(jìn)行刪除。例如要刪除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函數(shù),將員工名稱為劉小燕的記錄進(jìn)行了正確的刪除。




創(chuàng)建對象列

除了將整個對象作為表中的列來存儲的對象表之外,還可以為關(guān)系表中的某一列的屬性指定為對象類型,這種表稱為帶對象列的關(guān)系表。這種帶對象類型的關(guān)系表與對象表的主要不同在于對象表時通過使用對象標(biāo)識符來引用對象實(shí)例的,而對于列對象來說是沒有oracle對象標(biāo)識符的,列對象的對象實(shí)例屬于關(guān)系型數(shù)據(jù)庫中的記錄,具有一個rowid值作為標(biāo)識符。


定義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封裝了部門信息,可以看到具有部門編號,部門名稱和部門的地址信息,接下來創(chuàng)建一個名為emp_colobj的表,該表用來存放員工信息,但是在部門列中,將使用dept_obj對象類型作為列類型,可以再表中存儲關(guān)于部門的詳細(xì)信息。


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對象類型


在對象表中綁定了某個對象類型后,不能直接對對象表中的列及類型進(jìn)行操作,比如新增列或?qū)α羞M(jìn)行修改等,但是關(guān)系表中包含對象列類型則沒有這個限制,可以使用標(biāo)準(zhǔn)的ALTER TABLE語句來進(jìn)行操作.





使用對象視圖

為了創(chuàng)建一個對象視圖,必須首先創(chuàng)建一個與底層的數(shù)據(jù)表的列具有相匹配屬性的對象類型。


定義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;


在創(chuàng)建對象視圖時,必須要確定要使用的OID(對象標(biāo)識符).對象標(biāo)識符是用來唯一標(biāo)識一行對象的一個字符串,通過OID可以保證對對象實(shí)例引用的唯一性。OID標(biāo)識符僅在對象表和對象視圖上被創(chuàng)建,一旦一個OID被賦給了一個對象,那么將永遠(yuǎn)屬于那個對象。通常情況下,oracle會自動產(chǎn)生OID值,不需要要手工干預(yù),但是在定義對象視圖時,可以覆蓋系統(tǒng)產(chǎn)生OID的機(jī)制,更改為使用對象表的主鍵來替代.


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是對關(guān)系表的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);  --調(diào)用對象類型的成員方法

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語句,還可以根據(jù)type_name和supertype_name來查詢對象的繼承結(jié)構(gòu).

set pagesize 500;

select rpad (' ',3 * (LEVEL-1)) |from user_types where typecode='OBJECT' CONNECT BY PRIOR type_name=superty




2.修改對象類型

如果已經(jīng)基于對象類型建立了其他的對象類型或?qū)ο蟊?,那么在為對象類型增加或刪除屬性時,必須要使用cascade關(guān)鍵字.

--添加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;


--更改對象類型體,以便增加在對象類型規(guī)范中定義的方法

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關(guān)鍵字的alter type把它重新添加進(jìn)去.


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI