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)创建一个类型
 CREATE OR REPLACE TYPE PersonType AS OBJECT
(
 PersonName varchar(10),
 PersonSex varchar(2),
 PersonBirth date
) not final;
(2)派生一个类型
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是怎么比较的.

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

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值