oracle对象类型详解

注:有些文档将oracle的对象类型分为行对象类型和列对象类型,

行对象:行对象是指直接基于对象类型所建立的表

列对象:列对象是指在建表时指定了对象类型列的对象表

通过下面我们可以发现行对象应该就是基于抽象类型创建的关系表,列对象应该就是基于抽象类型创建的对象表。

 

一、抽象数据类型

1、创建类型

--地址类型

CREATE OR REPLACE TYPE AddressType AS OBJECT

(

Country varchar2(15),

City varchar2(20),

Street varchar2(30)

);

 

2、类型嵌套

--创建基于前一个类型的新的抽象数据类型:巨星类型

CREATE OR REPLACE TYPE SuperStarType AS OBJECT

(

StarName varchar2(30),

Address AddressType

);

 

3、基于抽象类型创建关系表

CREATE TABLE SuperStar

(

StarID varchar(10),

Star SuperStarType

);

 

4、基于抽象类型创建对象表

CREATE TABLE SuperStarObj of SuperStarType;

 

5、使用构造方法在表中插入记录

INSERT INTO SuperStar VALUES(''001'',SuperStarType(''Zidane'',AddressType(''France'',''Paris'',''People Street NO.1'')));

 

6、查询表中记录

(1)SQL> SELECT * FROM SuperStar;

 

STARID

----------

STAR(STARNAME, ADDRESS(COUNTRY, CITY, STREET))

--------------------------------------------------------------------------------

001

SUPERSTARTYPE(''Zidane'', ADDRESSTYPE(''France'', ''Paris'', ''People Street NO.1''))

 

(2)

SELECT s.StarID,s.Star.StarName,s.Star.Address.Country,s.Star.Address.City,s.Star.Address.Street FROM SuperStar s

 

STARID STAR.STARNAME STAR.ADDRESS.CO STAR.ADDRESS.CITY STAR.ADDRESS.STREET

---------- ------------------------------ --------------- -------------------- ---------------------

001 Zidane France Paris People Street NO.1

 

7、抽象数据类型的继承

(1)创建一个父类型

--(必须用NOT FINAL关键字指出是可以继承的类型)

CREATE OR REPLACE TYPE PersonType AS OBJECT

(

PersonName varchar(10),

PersonSex varchar(2),

PersonBirth date

) not final;

(2)--创建子类型(under 父类型)

CREATE OR REPLACE TYPE StudentType UNDER PersonType

(

StudentNO int,

StudentScore int

);

(3)查看数据字典

SQL> DESC StudentType

StudentType extends SYS.PERSONTYPE

Name

------------------------------------------------------------------------------

PERSONNAME

PERSONSEX

PERSONBIRTH

STUDENTNO

STUDENTSCORE

(4)创建对象表

CREATE TABLE student OF StudentType;

(5)向对象表中插入数据

INSERT INTO student VALUES(''Rose'',''nv'',to_date(''1983-05-02'',''yyyy-mm-dd''),1001,98);

(6) 查询数据

SQL> SELECT * FROM student;

 

PERSONNAME PE PERSONBIR STUDENTNO STUDENTSCORE

---------- -- --------- ---------- ------------

Rose nv 02-MAY-83 1001 98

########################################################################################################

########################################################################################################

二、可变数组

1、创建带有可变数组的表

(1)创建可变数组的基类型

CREATE OR REPLACE TYPE MingXiType AS OBJECT

(

GoodID varchar2(20),

InCount int,

ProviderID varchar(20)

);

(2)创建嵌套项类型的可变数组

CREATE OR REPLACE TYPE arrMingXiType AS VARRAY(100) OF MingXiType;

(3)创建一个主表

CREATE TABLE InStockOrder

(

OrderID varchar(15) Not Null Primary Key,

InDate date,

OperatorID varchar(15),

MingXi arrMingXiType

);

 

2、操作可变数组

(1)插入数据

INSERT INTO InStockOrder

VALUES(''200710110001'',TO_DATE(''2007-10-11'',''YYYY-MM-DD''),''007'',

arrMingXiType(MingXiType(''G001'',100,''1001''),

MingXiType(''G002'',888,''1002''))

);

(2)查询数据

SQL> SELECT * FROM InStockOrder;

 

ORDERID INDATE OPERATORID

--------------- --------- ---------------

MINGXI(GOODID, INCOUNT, PROVIDERID)

----------------------------------------------------------------------

200710110001 11-OCT-07 007

ARRMINGXITYPE(MINGXITYPE(''G001'', 100, ''1001''), MINGXITYPE(''G002'', 888, ''1002'')

(3)使用Table()函数

SQL> SELECT * FROM Table(SELECT t.MingXi FROM InStockOrder t

WHERE t.OrderID=''200710110001'');

 

GOODID INCOUNT PROVIDERID

-------------------- ---------- --------------------

G001 100 1001

G002 888 1002

(4)修改数据

UPDATE InStockOrder

SET MingXi=arrMingXiType(MingXiType(''G001'',200,''1001''),

MingXiType(''G002'',8888,''1002''))

WHERE OrderID=''200710110001''

注意:不能更新VARRAY中的单个元素,必须更新整个VARRAY

 

三、嵌套表

1、创建嵌套表

(1)创建嵌套表的基类型

CREATE OR REPLACE TYPE MingXiType AS OBJECT

(

GoodID varchar2(20),

InCount int,

ProviderID varchar(20)

) not final;

(2)创建嵌套表类型

CREATE OR REPLACE TYPE nestMingXiType AS TABLE OF MingXiType;

(3)创建主表,其中一列是嵌套表类型

CREATE TABLE InStockTable

(

OrderID varchar(15) Not Null Primary Key,

InDate date,

OperatorID varchar(15),

MingXi nestMingXiType

) Nested Table MingXi STORE AS MingXiTable;

 

2、操作嵌套表

(1)向嵌套表中插入记录

INSERT INTO InStockTable

VALUES(''20071012001'',TO_DATE(''2007-10-12'',''YYYY-MM-DD''),''007'',

nestMingXiType(MingXiType(''G003'',666,''1001''),

MingXiType(''G004'',888,''1002''),

MingXiType(''G005'',8888,''1003''))

);

(2)查询数据

SQL> SELECT * FROM InStockTable;

 

ORDERID INDATE OPERATORID

--------------- --------- ---------------

MINGXI(GOODID, INCOUNT, PROVIDERID)

----------------------------------------------------------------------------------------------------

20071012001 12-OCT-07 007

NESTMINGXITYPE(MINGXITYPE(''G003'', 666, ''1001''), MINGXITYPE(''G004'', 888, ''1002''), MINGXITYPE(''G005'', 8888, ''1003'')

(3)使用Table()函数

SQL> SELECT * FROM Table(SELECT T.MingXi FROM InStockTable t

WHERE OrderID=''20071012001'')

 

GOODID INCOUNT PROVIDERID

-------------------- ---------- --------------------

G003 666 1001

G004 888 1002

G005 8888 1003

(4)更新嵌套表中的数据

UPDATE Table(SELECT t.MingXi FROM InStockTable t WHERE OrderID=''20071012001'') tt

SET tt.InCount=1666 WHERE tt.GoodID=''G003'';

(5)删除表中数据

DELETE Table(SELECT t.MingXi FROM InStockTable t WHERE OrderID=''20071012001'') tt

WHERE tt.GoodID=''G003''

 

四、对象表

1、创建对象表

CREATE TABLE ObjectTable OF MingXiType;

2、向表中插入数据

INSERT INTO ObjectTable VALUES(''G001'',500,''P005'');

 

INSERT INTO ObjectTable VALUES(''G002'',1000,''P008'');

3、查询对象表中的记录

A 直接查询

SQL> SELECT * FROM ObjectTable;

 

GOODID INCOUNT PROVIDERID

-------------------- ---------- ---------------

G001 500 P005

G002 1000 P008

B 用VALUE()函数查询

SQL> SELECT VALUE(O) FROM ObjectTable O;

 

VALUE(O)(GOODID, INCOUNT, PROVIDERID)

------------------------------------------

MINGXITYPE(''G001'', 500, ''P005'')

MINGXITYPE(''G002'', 1000, ''P008'')

4、查看对象标志符(OID)

A REF操作符引用行对象

SQL> SELECT REF(t) FROM ObjectTable t;

 

REF(T)

--------------------------------------------------------------------------------

0000280209771F103ED34842478A9C439CDAEFEF6324B0ACF849F14BD7A8B52F4B0297D1C90040A9

5A0000

 

0000280209A2D3359E0F0C44B3AF652B944F8823F524B0ACF849F14BD7A8B52F4B0297D1C90040A9

5A0001

B 将OID用于创建外键

CREATE TABLE Customer

( CustomerID varchar(10) PRIMARY KEY,

CustomerName varchar(20),

CustomerGoods REF MingXiType SCOPE IS ObjectTable,--引用MingXiType外键,关联的是OID的值

CustomerAddress varchar(20)

);

C 向Customer表中插入数据,此表将从上面创建的对象表中引用数据

INSERT INTO Customer SELECT ''007'',''Yuanhy'',REF(O),''France''

FROM ObjectTable O

WHERE GoodID=''G001'';

D 查询Customer表

SQL> SELECT * FROM Customer;

 

CUSTOMERID CUSTOMERNAME

---------- --------------------

CUSTOMERGOODS

-----------------------------------------------------------------------------

CUSTOMERADDRESS

--------------------

007 Yuanhy

0000220208771F103ED34842478A9C439CDAEFEF6324B0ACF849F14BD7A8B52F4B0297D1C9

France

E 用DEREF操作符返回对象的值

SQL> SELECT CustomerID,CustomerName,DEREF(t.CustomerGoods),CustomerAddress

2 FROM Customer t;

 

CUSTOMERID CUSTOMERNAME

---------- --------------------

DEREF(T.CUSTOMERGOODS)(GOODID, INCOUNT, PROVIDERID)

----------------------------------------------------------------------------

CUSTOMERADDRESS

--------------------

007 Yuanhy

MINGXITYPE(''G001'', 500, ''P005'')

France

 

五、对象视图

将关系表化装成对象表

1、 创建对象视图

A 创建基于关系表父表的对象类型

CREATE OR REPLACE TYPE depttype AS OBJECT

(

deptid number(10),

deptname varchar(30),

loc number(10)

);

B 创建基于关系表的对象视图

CREATE VIEW deptview OF depttype WITH OBJECT OID(deptid) AS

SELECT department_id,department_name,location_id FROM dept;

C 查询视图

SQL> SELECT * FROM deptview;

 

DEPTID DEPTNAME LOC

---------- ------------------------------ ----------

10 Administration 1700

20 Marketing 1800

30 Purchasing 1700

40 Human Resources 2400

50 Shipping 1500

60 IT 1400

70 Public Relations 2700

 

SQL> select ref(t) from deptview t;

 

REF(T)

----------------------------------------------------------------------------------------------------

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

2、创建引用视图(类似于关系表创建一个从表)

CREATE VIEW empview AS SELECT MAKE_REF(deptview,department_id) deptOID,employee_id,

first_name,last_name FROM emp;

 

查询对象视图empview

SQL> SELECT * FROM empview;

 

DEPTOID

----------------------------------------------------------------------------------------------------

EMPLOYEE_ID FIRST_NAME LAST_NAME

----------- -------------------- -------------------------

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

100 Steven King

 

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

101 Neena Kochhar

 

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

102 Lex De Haan

 

00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

103 Alexander Hunold

Oracle对象类型也有属性和方法.

创建对象类型与创建表很相似,只是实际上不为存储的数据分配空间:

不带方法的简单对象类型:

 

CREATE TYPE type_name as OBJECT (

column_1 type1,

column_2 type2,

...

);

注意:AS OBJECT

创建好对象类型之后,就可以在创建表的时候,使用该类型了,如:

 

CREATE TYPE HUMAN AS OBJECT(

NAME VARCHAR2(20),

SEX VARCHAR2(1),-- F : FEMALE M:MALE

BIRTHDAY DATE,

NOTE VARCHAR2(300)

)

稍后,可以用下面的语句查看:

 

SELECT * FROM USER_OBJECTS WHERE OBJECT_TYPE = ''TYPE''

CREATE TABLE STUDENTS(

GUID NUMBER NOT NULL,

STUDENTS HUMAN

)

此下省去两个Trigger.

插入数据的时候,可以如下:

 

INSERT INTO STUDENTS (STUDENT) VALUES (HUMAN(''xling'',''M'',TO_DATE(''20060101'',''YYYYMMDD''),''测试''))

注意:HUMAN(''xling'',''M'',TO_DATE(''20060101'',''YYYYMMDD''),''测试''),这是个默认的构造函数.

如果想选出性别为女(F)的记录,可以如下:

 

SELECT * FROM STUDENTS S WHERE S.STUDENT.SEX = ''F''

注意:不能写成:SELECT * FROM STUDENTS WHERE STUDENT.SEX = ''F'' 这样会报如下错误:ORA-00904: "STUDENT"."SEX": 标识符无效

 

对象类型表:每条记录都是对象的表,称为对象类型表.它有两个使用方法:1,用作只有一个对象类型字段的表.2,用作具有对象类型字段的标准关系表.

语法如下:

 

CREATE TABLE table_name OF object_type;

例如:

 

CREATE TABLE TMP_STUDENTS OF HUMAN;

用DESC TMP_STUDENTS,可以看到它的字段结构和HUMAN的结构一样.

对象类型表有两个优点:1,从某种程度上简化了对象的使用,因为对象表的字段类型与对象类型是一致的,所以,不需要用对象名来修饰对象属性,可以把数据插入对象类型表,就像插入普通的关系表中一样:

INSERT INTO TMP_STUDENTS VALUES (''xling'',''M'',TO_DATE(''20060601'',''YYYYMMDD''),''对象类型表'');

当然也可用如下方法插入:

INSERT INTO TMP_STUDENTS VALUES (HUMAN(''snow'',''F'',TO_DATE(''20060102'',''YYYYMMDD''),''用类型的构造函数''));

第二个特点是:对象表是使用对象类型作为模板来创建表的一种便捷方式,它可以确保多个表具有相同的结构.

对象类型表在:USER_TABLES表里是查不到的,而在USER_OBJECTS表里可以查到,而且OBJECT_TYPE = ''TABLE''

类型在定义的时候,会自动包含一个方法,即默认的构造器.构造器的名称与对象的名称相同,它带有变量与对象类型的每个属性相对应.

 

对象类型的方法:

 

CREATE TYPE type_name AS OBJECT (

column1 column_type1,

column2 column_type2,

... ,

MEMBER FUNCTION method_name(args_list) RETURN return_type,

...

)

注意:是MEMBER FUNCTION,(当然,也可是MEMBER PROCEDURE,没有返回值)

和包(PACKAGE)一样,如果对象类型有方法的话,还要声明一个BODY:

 

CREATE TYPE BODY type_name AS

 

MEMBER FUNCTION method_name RETURN return_type {AS | IS}

variable declareations..

BEGIN

CODE..

RETURN return_value;

END;//END MEMBER FUNCTION

...

END;//END TYPE BODY

如下所示:

 

CREATE TYPE HUMAN AS OBJECT(

NAME VARCHAR2(20),

SEX VARCHAR2(1),-- F : FEMALE M:MALE

BIRTHDAY DATE,

NOTE VARCHAR2(300),

 

MEMBER FUNCTION GET_AGE RETURN NUMBER

)

--BODY

CREATE TYPE BODY HUMAN AS

MEMBER FUNCTION GET_AGE RETURN NUMBER AS

V_MONTHS NUMBER;

BEGIN

SELECT FLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12) INTO V_MONTHS FROM DUAL;

RETURN V_MONTHS;

END;

END;

 

 

注意:BODY的格式,不是AS OBJECT,也不是用小括号括起来的.MEMBER FUNCTION 后的AS或IS不能省略.

还以STUDENTS表为例(注:如果类型以被某个表使用,是不能修改的,必须把相关的表删除,然后把类型删除,在一个一个新建,这里就省略了,参见前文所述)

SELECT S.STUDENT.GET_AGE() FROM STUDENTS S

 

在提起注意:表名一定要有别名.GET_AGE()的括号不能省略,否则会提示错误.

下面演示在一个匿名过程中的使用情况:

SET SERVEROUTPUT ON

DECLARE

AA HUMAN;

AGE NUMBER;

BEGIN

AA := HUMAN(''xingFairy'',''M'',TO_DATE(''19830714'',''YYYYMMDD''),''过程'');

AGE := AA.GET_AGE();

DBMS_OUTPUT.PUT_LINE(AGE);

END;

映射方法:

映射方法是一种不带参数,并返回标准的标量Oracle SQL数据类型的方法,如NUMBER,VARCHAR2,Oracle将间接地使用这些方法执行比较运算.

映射方法最重要的一个特点是:当在WHERE或ORDER BY等比较关系子句中使用对象时,会间接地使用映射方法.

映射方法的声明只过是在普通方法声明的前面加一个 MAP而以,注意:映射方法是一种不带参数的方法.

MAP MEMBER FUNCTION function_name RETURN return_type

修改前文提到的HUMAN类型:

--映射方法 MAP

 

CREATE TYPE HUMAN AS OBJECT(

NAME VARCHAR2(20),

SEX VARCHAR2(1),-- F : FEMALE M:MALE

BIRTHDAY DATE,--注册日期 

REGISTERDAY DATE,

NOTE VARCHAR2(300),

 

MEMBER FUNCTION GET_AGE RETURN NUMBER,

MAP MEMBER FUNCTION GET_GRADE RETURN NUMBER

)

CREATE TYPE BODY HUMAN AS

-----------------------

MEMBER FUNCTION GET_AGE RETURN NUMBER AS

V_MONTHS NUMBER;

BEGIN

SELECT FLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12) INTO V_MONTHS FROM DUAL;

RETURN V_MONTHS;

END;

------------------------

MAP MEMBER FUNCTION GET_GRADE RETURN NUMBER AS

BEGIN

RETURN MONTHS_BETWEEN(SYSDATE,BIRTHDAY);

END;

END;

插入数据:

 

INSERT INTO STUDENTS (STUDENT) VALUES (HUMAN(''xling'',''M'',TO_DATE(''19830714'',''YYYYMMDD''),TO_DATE(''20020915'',''YYYYMMDD''),''测试MAP方法''));

INSERT INTO STUDENTS (STUDENT) VALUES (HUMAN(''fairy'',''M'',TO_DATE(''19830714'',''YYYYMMDD''),TO_DATE(''20010915'',''YYYYMMDD''),''测试MAP方法''));

INSERT INTO STUDENTS (STUDENT) VALUES (HUMAN(''snow'',''M'',TO_DATE(''19830714'',''YYYYMMDD''),TO_DATE(''20020915'',''YYYYMMDD''),''测试MAP方法''));

在执行上面的操作后,用下面这个SELECT语句可以看出映射方法的效果:

SELECT S.STUDENT.NAME,S.STUDENT.GET_GRADE() FROM STUDENTS S ORDER BY STUDENT

它是按MAP方法GET_GRADE()的值进行排序的.注意是ORDER BY STUDENT,在提起一次需要注意,一定要用表的别名,方法后的括号不能省略,即使没有参数.

如果想以MAP方法的结果为条件,可以如下:

 

SELECT S.STUDENT.NAME,S.STUDENT.GET_GRADE() FROM STUDENTS S WHERE S.STUDENT.GET_GRADE() > 50

SELECT S.STUDENT.NAME,S.STUDENT.GET_GRADE() FROM STUDENTS S WHERE STUDENT > HUMAN(NULL,NULL,NULL,TO_DATE(''20020101'',''YYYYMMDD''),NULL);

排序方法:

先说一下SELF,Oracle里对象的SELF和JAVA里的this是同一个意思.

对象的排序方法具有一个与对象类型相同的参数,暂称为ARG1,用于和SELF对象进行比较.如果调用方法的SELF对象比ARG1小,返回负值,如果相等,返回0,如果SELF大于ARG1,则返回值大于0.

--映射方法 MAP

 

CREATE TYPE HUMAN AS OBJECT(

NAME VARCHAR2(20),

SEX VARCHAR2(1),-- F : FEMALE M:MALE

BIRTHDAY DATE,

REGISTERDAY DATE,

NOTE VARCHAR2(300),

 

MEMBER FUNCTION GET_AGE RETURN NUMBER,

ORDER MEMBER FUNCTION MATCH(I_STUDENT IN HUMAN) RETURN NUMBER

)

CREATE TYPE BODY HUMAN AS

-----------------------

MEMBER FUNCTION GET_AGE RETURN NUMBER AS

V_MONTHS NUMBER;

BEGIN

SELECT FLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12) INTO V_MONTHS FROM DUAL;

RETURN V_MONTHS;

END;

------------------------

ORDER MEMBER FUNCTION MATCH(I_STUDENT IN HUMAN) RETURN NUMBER AS

BEGIN

RETURN REGISTERDAY - I_STUDENT.REGISTERDAY;

END;

END;

注意:在声明的时候,ORDER方法的参数类型要和SELF的类型一致.

SET SERVEROUTPUT ON

DECLARE

S1 HUMAN;

S2 HUMAN;

BEGIN

 

S1 := HUMAN(''xling'',NULL,NULL,TO_DATE(''20020915'',''YYYYMMDD''),NULL);

S2 := HUMAN(''snow'',NULL,NULL,TO_DATE(''20010915'',''YYYYMMDD''),NULL);

 

IF S1 > S2 THEN

DBMS_OUTPUT.PUT_LINE(S1.NAME);

ELSIF S1 < S2 THEN

DBMS_OUTPUT.PUT_LINE(S2.NAME);

ELSE

DBMS_OUTPUT.PUT_LINE(''EQUAL'');

END IF;

END;

注意S1 和 S2是怎么比较的.

映射方法具有效率方面的优势,因为它把每个对象与单个标量值联系在一起;排序方法有灵活方面的优势,它可以在两个对象之间进行任意复杂的比较.排序方法比映射方法的速度慢.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值