Oracle自定义数据类型

前端之家收集整理的这篇文章主要介绍了Oracle自定义数据类型前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

注:为了更加清晰的看清有些没有格式的sql语句,本人修改了原文作者文章的部分sql格式

因不知原文出处,链接就不附带了...望体谅


一:Oracle中的类型有很多种,主要可以分为以下几类:

1、字符串类型。如:char、nchar、varchar2、nvarchar2。
2、数值类型。如:int、number(p,s)、integer、smallint。
3、日期类型。如:date、interval、timestamp。
4、PL/sql类型。如:pls_integer、binary_integer、binary_double(10g)、binary_float(10g)、boolean。plsql类型是不能在sql环境中使用的,比如建表时。
5、自定义类型:type / create type。

二:type / create type 区别联系

相同:

可用用关键字create type 或者直接用type定义自定义类型,

区别:

create type 变量 as table of 类型

--

create type 变量 as object(

字段1 类型1,字段2 类型2

);

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

与 type 变量 is table of 类型

--

type 变量 is record(

字段1 类型1,字段2 类型2

);

区别是 用 create 后面用 as,若直接用 type 后面用is

create 是创 object,而 type 是创record .

另 type用在语句块中,而create 是的独立的.

一般定义object的语法:

用

create type 自定义表类型A as table of 自定义Object类型A

和

create type 自定义Object类型A as object(

字段1 类型1,字段2 类型2

);

与

type 自定义表类型B is table of 类型

和

type 自定义Object类型B is record(

字段1 类型1,字段2 类型2);

自定义类型一般分为两中,object类型和table类型.object类似于一个recored,可以表示一个表的一行数据,object的字段就相当与表的字段.自定义的table类型需要用的已经定义好的object类型.


三:type record用法概述

type 自定义Object类型B is record(

字段1 类型1,字段2 类型2);

3.1:什么是记录(Record)?
由单行多列的标量构成的复合结构。可以看做是一种用户自定义数据类型。组成类似于多维数组。
将一个或多个标量封装成一个对象进行操作。是一种临时复合对象类型。

记录可以直接赋值。RECORD1 :=RECORD2;
记录不可以整体比较.
记录不可以整体判断为空。

3.2:%ROWTYPE和记录(Record)?
请区别%ROWTYPE和记录(Record)类型。%ROWTYPE可以说是Record的升级简化版。
区别在与前者结构为表结构,后者为自定义结构。二者在使用上没有很大区别。前者方便,后者灵活。在实际中根据情况来具体决定使用。
Record + PL/sql表可以进行数据的多行多列存储。

3.3:如何创建和使用记录?

①创建记录类型
语法:

  1. TYPE记录名ISRECORD
  2.  (
  3. filed1type1[NOTNULL][:=eXPr1],
  4.  .......,
  5.  filedNtypen[NOTNULL][:=exprn]

其中,filed1是标量的名字。
②声明记录类型变量:
记录类型变量名 记录类型
③填充记录。
④访问记录成员
记录类型变量名.filed1
.........
记录类型变量名.filedN
注意:
表字段类型修改后,还需要修改记录字段类型,有时候可能会忘记,从而出现错误。对于记录内每个字段(filed1...),可以指定也可以使用%TYPE和%ROWTYPE动态指定记录字段类型。好处是表字段发生变化,记录字段自动改变。但是,由于每次执行前,遇到%TYPR或%ROWTYPE,数据库系统都会去查看对应表字段类型,会造成一定的数据库开销,如果系统中大量使用记录类型,则对性能会有一定影响。另外如果删除了某一字段,而自定义记录中使用了该字段,也会有可能忘记删除该字段。对数据库负荷偏低的系统,性能问题一般可以不重点关注,但是对于高负荷数据库服务器,各个环节都要考虑性能问题,每处节省一点出来,性能整体就有很大提高。

语法:

  1. TYPE记录名ISRECORD
  2. (
  3. filed1table.Filed%Type[NOTNULL][:=eXPr1],
  4. filed2table.Filed%Type[NOTNULL][:=eXPr1],
  5. .......,
  6. filedntable.Filed%Type[NOTNULL][:=exprn]
  7. );

例子:记录可以整体赋值

  1. /*connscott/tiger
  2. CreateTableempaAsSelect*Fromemp;
  3. */
  4. Declare
  5. TypeEmpTypeisRecord(
  6. EMPNOnumber(4),
  7. ENAMEvarchar2(10),
  8. JOBvarchar2(15),
  9. SALnumber(7,2),
  10. DEPTNOnumber(2)
  11. );
  12. EmpRec1EmpType;
  13. EmpRec2EmpType;
  14. Begin
  15. EmpRec1.Empno:=7369;
  16. EmpRec1.Ename:='SMITH';
  17. EmpRec1.Job:='CLERK';
  18. EmpRec1.Sal:=800;
  19. EmpRec1.Deptno:=10;
  20. EmpRec2:=EmpRec1;
  21. DBMS_output.put_line(EmpRec2.empno);
  22. End;
例子:记录不可以整体比较,只可以比较记录字段
  1. Declare
  2. TypeEmpTypeisRecord(
  3. EMPNOnumber(4),
  4. ENAMEvarchar2(10),
  5. JOBvarchar2(15),
  6. SALnumber(7,
  7. DEPTNOnumber(2)
  8. );
  9. EmpRec1EmpType;
  10. EmpRec2EmpType;
  11. Begin
  12. EmpRec1.Empno:=7369;
  13. EmpRec1.Ename:='SMITH';
  14. EmpRec1.Job:='CLERK';
  15. EmpRec1.Sal:=800;
  16. EmpRec1.Deptno:=10;
  17. ifEmpRec1.sal<EmpRec2.salthen
  18. DBMS_output.put_line('XiaoXiaoXiao');
  19. endif;
  20. End;
@H_890_403@例子:记录不可以整体判断为空,只可以判断记录字段。

  1. Declare
  2. TypeEmpTypeisRecord(
  3. EMPNOnumber(4),
  4. DEPTNOnumber(2)
  5. );
  6. EmpRecEmpType;
  7. Begin
  8. ifEmpRec.enameisnullthen
  9. DBMS_output.put_line('KongKongKong');
  10. endif;
  11. End;
@H_890_403@例子:使用%TYPE和%ROWTYPE动态指定记录字段。

  1. /*connscott/tiger
  2. CreateTableempaAsSelect*Fromemp;
  3. */
  4. DECLARE
  5. TypeMyRecTypeIsRecord
  6. (
  7. RENOEMPA.EMPNO%Type,
  8. RENAMEEMPA.ENAME%Type,
  9. RJOBEMPA.JOB%Type
  10. );
  11. EmpRecMyRecType;
  12. Begin
  13. SelectEMPNO,ENAME,JOBInToEmpRecFromempaWhereempa.EMPNO='7369';
  14. IfEmpRec.RJOB='CLERK'Then
  15. DBMS_OUTPUT.PUT_LINE('Name:'||EmpRec.RENAME);
  16. EndIf;
  17. End;
@H_890_403@例子:数据集中的记录和记录类型中的数据关系。

  1. DECLARE
  2. TypeMyRecTypeIsRecord
  3. (
  4. RENOEMPA.EMPNO%Type,
  5. RENAMEEMPA.ENAME%Type,
  6. RJOBEMPA.JOB%Type
  7. );
  8. EmpRecMyRecType;
  9. vJobEMPA.JOB%Type;
  10. Begin
  11. SelectEMPNO,JOBInToEmpRecFromempaWhereempa.EMPNO='7369';
  12. DBMS_OUTPUT.PUT_LINE('MyRecType.RJOB:'||EmpRec.RJOB);
  13. EmpRec.RJOB:='修改值后';
  14. DBMS_OUTPUT.PUT_LINE('MyRecType.RJOB:'||EmpRec.RJOB);
  15. SelectJOBInTovJobfromempaWhereempa.EMPNO=EmpRec.RENO;
  16. DBMS_OUTPUT.PUT_LINE('EMPA.JOB:'||vJob);
  17. End;
  18. /

3.4:使用记录向表中插入数据?
根据表结构合理安排记录字段。比如主外键。
如果用记录(RECORD)插入数据,那么只能使用记录成员;如果用%ROWTYPE插入数据,可以直接使用%ROWTYPE。
例子:使用记录成员向表中插入数据

  1. DECLARE
  2. TypeMyRecTypeIsRecord
  3. (
  4. RENOEMPA.EMPNO%Type,
  5. RENAMEVARCHAR2(10),
  6. RJOBEMPA.JOB%Type
  7. );
  8. EmpRecMyRecType;
  9. Begin
  10. SelectEMPNO,JOBInToEmpRecFromempaWhereempa.EMPNO='7369';
  11. DBMS_OUTPUT.PUT_LINE(EmpRec.RENO||''||EmpRec.RENAME||''||EmpRec.RJOB);
  12. EmpRec.RENO:=1001;
  13. EmpRec.RENAME:='杰克';
  14. EmpRec.RJOB:='办事员';
  15. InsertInToempa(EMPNO,JOB)Values(EmpRec.RENO,EmpRec.RENAME,EmpRec.RJOB);
  16. SelectEMPNO,JOBInToEmpRecFromempaWhereempa.EMPNO='1001';
  17. DBMS_OUTPUT.PUT_LINE(EmpRec.RENO||''||EmpRec.RENAME||''||EmpRec.RJOB);
  18. End;

3.5:使用记录更新数据?
如果用记录(RECORD)更新数据,那么只能使用记录成员;
如果用%ROWTYPE更新数据,可以直接使用%ROWTYPE。

例子:使用%ROWTYPE向表中插入数据

  1. DECLARE
  2. vEmpempa%RowType;
  3. Begin
  4. Select*InTovEmpFromempaWhereempa.EMPNO='7369';
  5. UpDateempaSetROW=vEmpWhereEMPNO=1001;
  6. End;
@H_890_403@3.6:使用记录删除数据:删除记录时,只能在delete语句的where子句中使用记录成员。


四:type table用法

4.1:定义

type 变量 is table of 类型

TYPE orders_type IS TABLE OFall_orders%ROWTYPE;

4.2:用法

1. TYPE tabletypeISTABLEOFtypeINDEXBYBINARY_INTEGER;

定义:

TYPEt_charTable IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;

引用:tableName(index);

例子:

1.

  1. declare
  2. typet_tableistableofvarchar2(10)indexbyBINARY_integer;
  3. MyTabt_table;
  4. begin
  5. MyTab(1):='A';
  6. MyTab(2):='B';
  7. MyTab(3):='C';
  8. DBMS_OUTPUT.PUT_LINE('Firstindex:'||''||mytab(1)||'');
  9. end;
  10. --
  11. DECLARE
  12. TYPEt_StudentTableISTABLEOFstudents%ROWTYPEINDEXBYBINARY_INTEGER;
  13. v_Studentst_StudentTable;
  14. BEGIN
  15. SELECT*INTOv_Students(1100)
  16. FROMstudents
  17. WHEREid=1100;
  18. DBMS_OUTPUT.PUT_LINE(v_Students(1100).OUUSRNM);
  19. END;
2.--record table综合使用
  1. /*connscott/tiger
  2. Createtableempaasselect*fromemp;
  3. */
  4. --例子:
  5. Declare
  6. TypeRecTypeIsRecord
  7. (
  8. rnoempa.empno%type,
  9. rnameempa.ename%type,
  10. rsalempa.sal%type
  11. );
  12. TypeTabTypeIsTableOfRecTypeIndexByBinary_Integer;
  13. MyTabTabType;
  14. vNNumber;
  15. Begin
  16. --填充
  17. vN:=1;
  18. ForvarRIn(Select*FromempaOrderByempnoASC)
  19. Loop
  20. MyTab(vN).rno:=varR.empno;
  21. MyTab(vN).rname:=varR.ename;
  22. MyTab(vN).rsal:=varR.sal;
  23. vN:=vN+1;
  24. EndLoop;
  25. --访问
  26. vN:=MyTab.First;
  27. ForvarRInvN..MyTab.count
  28. Loop
  29. DBMS_OUTPUT.PUT_LINE(vN||''||MyTab(vN).rno||''||MyTab(vN).rname||''||MyTab(vN).rsal);
  30. vN:=MyTab.Next(vN);
  31. EndLoop;
  32. End;

注意:

Oracle中index by binary_integer的作用

如语句:type numbersis table of number index by binary_integer;其作用是,加了”index by binary_integer ”后,numbers类型的下标就是自增长,numbers类型在插入元素时,不需要初始化,不需要每次extend增加一个空间。而如果没有这句话“index by binary_integer”,那就得要显示对初始化,且每插入一个元素到numbers类型的table中时,都需要先extend.

示例:没加“index bybinary_integer”时:

  1. declare
  2. typenumbersistableofnumber;
  3. nnumbers:=numbers();
  4. begin
  5. n.extend;
  6. n(1):=2;
  7. n.extend;
  8. n(2):=3;
  9. foriin1..n.countloop
  10. dbms_output.put_line(n(i));
  11. endloop;
  12. end;
  13. --输出:2,3
而如果加了“index by binary_integer”代码如下写就可以达到上面的效果
  1. declare
  2.   typenumbersistableofnumberindexbybinary_integer;
  3.   nnumbers;
  4.   begin
  5.   n(1):=2;
  6.   n(2):=3;
  7.   foriin1..n.countloop
  8.   dbms_output.put_line(n(i));
  9.   endloop;
  10.   end;

五:create type 用法

5.1:定义

概念

方法:是在对象类型说明中用关键字 MEMBER 声明的子程序

方法是作为对象类型定义组成部分的一个过程或函数

方法不能与对象类型或其任何属性同名

与数据包程序相似,大多数方法有两个部分

  1. CREATE[ORREPLACE]TYPE<typename>ASOBJECT
  2. (attribute1datatype,
  3. :
  4. attributeNdatatype
  5. MEMBERPROCEDURE<methodname>(parameter,mode,datatype),
  6. MEMBERFUNCTION<methodname>(parameter,datatype)RETURNdatatype,
  7. PRAGMARESTRICT_REFERENCES(<methodname>,WNDS/RNDS/WNPS/RNPS)
  8. );

说明:PRAGMA RESTRICT_REFERENCES指定MEMBER方法按以下模式之一 操作:

–WNDS (不能写入数据库状态) 不能修改数据库

–RNDS (不能读出数据库状态) 不能执行查询

–WNPS (不能写入数据包状态) 不能更改数据包变量的值

–RNPS (不能读出数据包状态) 不能引用数据包变量的值

例:

  1. createorreplacetypeFLIGHT_SCH_TYPEasobject
  2. (FLIGHTNOVARCHAR2(4),AIRBUSNOVARCHAR2(5),
  3. ROUTE_CODEVARCHAR2(7),DEPRT_TIMEVARCHAR2(10),
  4. JOURNEY_HURSVARCHAR2(10),FLIGHT_DAY1NUMBER(1),
  5. FLIGHT_DAY2NUMBER(1),
  6. MemberfunctionDAYS_FN(FLIGHT_DAY1innumber)returnvarchar2,
  7. Pragmarestrict_references(DAYS_FN,WNDS));

创建对象类型方法主体

  1. CREATE[ORREPLACE]TYPEBODY<typename>ASMEMBERFUNCTION<methodname>(parameterdataype)RETURN<datatype>IS<PL/sql_block>;
  2. MEMBERPROCEDURE<methodname>(parameterdatatype);
  3. END;

例:

  1. createorreplacetypebodyFLIGHT_SCH_TYPEas
  2. memberfunctionDAYS_FN(FLIGHT_DAY1innumber)returnvarchar2
  3. is
  4. disp_dayvarchar2(20);
  5. begin
  6. ifflight_day1=1then
  7. disp_day:='Sunday';
  8. elsifflight_day1=2then
  9. disp_day:='Monday';
  10. elsifflight_day1=3then
  11. disp_day:='Tuesday';
  12. elsifflight_day1=4then
  13. disp_day:='Wednesday';
  14. elsifflight_day1=5then
  15. disp_day:='Thursday';
  16. elsifflight_day1=6then
  17. disp_day:='Friday';
  18. elsifflight_day1=7then
  19. disp_day:='Saturday';
  20. endif;
  21. returndisp_day;
  22. end;
  23. end;

调用对象方法基于类型创建表后,就可以在查询调用对象方法

A. 创建基于对象的表语法:

create table <表名> of <对象类型>:此表具有该类型和member方法的所有属性,我们不能通过DBA STUdio的表数据编辑器来编辑数据。

例:

  1. createtableFLIGHT_SCH_TABofFLIGHT_SCH_TYPE
  2. insertintoFLIGHT_SCH_TABvalues('SL36','AB02','SAN-LOU','5','13:30',3,6);

B.访问对象表中的MEMBER语法:

SELECT <columnname>,<aliasname>.<methodname(parameters)> FROM <tablename> <aliasname>;

例:

  1. selectflightno,route_code,f.days_fn(flight_day1)asFLIGHTDAYfromFLIGHT_SCH_TABf;

C.关系表中的字段为对象类型

create table FLIGHT_SCH_TABS(FLIGHT_DET FLIGHT_SCH_TYPE,FLIGHT_DESC varchar2(20)) ;

注:插入数据,对于对象类型的字段的值,需要通过构造函数来得到。对象类型名称(成员1,..成员n)

例:

  1. insertintoFLIGHT_SCH_TABSvalues(FLIGHT_SCH_TYPE('SL36',6),'DESC1');

D.访问关系表中的Member方法此处的关系表:指表中有字段为对象类型

SELECT <columnname>,<aliasname>.<columnname>.<methodname (parameters)>FROM <tablename> <aliasname>;

例:

  1. selectf.flight_det.FLIGHTNO,f.flight_det.ROUTE_CODE,f.flight_det.DAYS_FN(f.flight_det.FLIGHT_DAY1)FLIGHTDAYfromflight_sch_tabsf;

1.声明简单类型内容包括:A.对象类型的创建 B.基于对象的表的创建插入与访问 C.关系对象表的创建插入与访问

2.通过value运算符访问基于类型的表select value(<aliasname>) From <objecttable> <aliasname>

例:

select value(A) FROM FLIGHT_SCH_TAB A;--返回的是对象

select * from FLIGHT_SCH_TAB;--返回的是单个的值

3 REF运算符使您可以引用对象表中现有行的OID值.REF运算符将表别名作为输入,并且为行对象返回OID

语法:select REF(<aliasname>) from <objecttable> <aliasname>

例:

  1. selectref(a)fromFLIGHT_SCH_TABa;注:FLIGHT_SCH_TAB是基于对象的表

4.声明复合类型

CREATE TYPE name_type AS OBJECT(name VARCHAR2(20),address address_type);

5.定义对象之间的关系也是通过关键字REF,前面我们通过REF查询了基于对象的表中的对象的OID值,这里我们讲REF的另一个用途,即通过REF来定义对象之间的关系,称为引用的REF允许您创建行对象指针.它将创建对被引用对象位置的引用i该指针用于查询、更新或删除对象iREF由目标对象的OID、数据库标识符(列)和对象表构成iOID用于创建使用REF和DEREF运算符的外键列的关系

isql和PL/sql语句必须使用REF函数来处理对象引用

可按如下步骤关联两个表

1. 创建对象类型,下面我们会创建另一个表,这个表的一个字段的类型为此类型

create or replace type type_class as object(classid varchar2(10),classname varchar2(10))

2. 创建基于此类型的表

create table tbl_type_class of type_class

3.创建具有外键列的关系表,有一个外键将引用1中定义的类型,并且该外键的值在2中已有的数据已经存在

create table tbl_student_ref(stuid  varchar2(20),stuname varchar2(20),age number(10),grade ref type_class scope is tbl_type_class)

4.将数据插入到对象表中begin insert into tbl_type_class values('gid1','gname1');

insert into tbl_type_class values('gid2','gname2');
commit;
end;

5.将数据插入到关系对象表中,必须从上面创建的对象表中引用数据;

insert into tbl_student_ref select 'stuid1','stuname1',20,ref(a) from tbl_type_class a where classid='gid1'

注:下面的方法是不行的!

insert  into   tbl_student_ref   values( 'stuid2','stuname2',select ref(a) from tbl_type_class a where classid='gid1')

6.服从值若要查看引用的值,则需要使用DEREF运算符i语法SELECT DEREF(<列名>.<列名>)FROM <表名> <别名>;

例:

select   deref(grade)   from   tbl_student_ref

简单用法

  1. createorreplacetypetyp_calendarasobject(
  2. 年varchar2(8),
  3. 月varchar2(8),
  4. 星期日varchar2(8),
  5. 星期一varchar2(8),
  6. 星期二varchar2(8),
  7. 星期三varchar2(8),
  8. 星期四varchar2(8),
  9. 星期五varchar2(8),
  10. 星期六varchar2(8),
  11. 本月最后一日varchar2(2)
  12. );
  13. --这种类型可以在表结构定义的时候使用:
  14. createtabletcalendaroftyp_calendar;
  15. --插入数据测试:
  16. sql>insertintotcalendar
  17. 2selecttyp_calendar('2010','05','1','2','3','4','6','7','31')fromdual
  18. 3/
  19. --注意:插入的数据需要用typ_calendar进行转换。
  20. 1rowinserted
  21. --查看结果
  22. sql>select*fromtcalendar;
  23. 年月星期日星期一星期二星期三星期四星期五星期六本月最后一日
  24. ------------------------------------------------------------------------------------
  25. 201005123456731

复杂用法

一、抽象数据类型

1、创建类型

--地址类型

  1. CREATEORREPLACETYPEAddressTypeASOBJECT
  2. (
  3. Countryvarchar2(15),
  4. Cityvarchar2(20),
  5. Streetvarchar2(30)
  6. );

2、类型嵌套

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

  1. CREATEORREPLACETYPESuperStarTypeASOBJECT
  2. (
  3. StarNamevarchar2(30),
  4. AddressAddressType
  5. );

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

  1. CREATETABLESuperStar
  2. (
  3. StarIDvarchar(10),
  4. StarSuperStarType
  5. );

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

  1. CREATETABLESuperStarObjofSuperStarType;

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

  1. INSERTINTOSuperStarVALUES(''001'',SuperStarType(''Zidane'',AddressType(''France'',''Paris'',''PeopleStreetNO.1'')));

6、查询表中记录

  1. (1)sql>SELECT*FROMSuperStar;
  2. STARID
  3. ----------
  4. STAR(STARNAME,ADDRESS(COUNTRY,CITY,STREET))
  5. --------------------------------------------------------------------------------
  6. 001
  7. SUPERSTARTYPE(''Zidane'',ADDRESSTYPE(''France'',''PeopleStreetNO.1''))
  8. (2)
  9. SELECTs.StarID,s.Star.StarName,s.Star.Address.Country,s.Star.Address.City,s.Star.Address.StreetFROMSuperStars
  10. STARIDSTAR.STARNAMESTAR.ADDRESS.COSTAR.ADDRESS.CITYSTAR.ADDRESS.STREET
  11. ------------------------------------------------------------------------------------------------
  12. 001ZidaneFranceParisPeopleStreetNO.1

7、抽象数据类型的继承

(1)创建一个类型

  1. CREATEORREPLACETYPEPersonTypeASOBJECT
  2. (
  3. PersonNamevarchar(10),
  4. PersonSexvarchar(2),
  5. PersonBirthdate
  6. )notfinal;

(2)派生一个类型

  1. CREATEORREPLACETYPEStudentTypeUNDERPersonType
  2. (
  3. StudentNOint,
  4. Studentscoreint
  5. );

(3)查看数据字典

  1. sql>DESCStudentType
  2. StudentTypeextendsSYS.PERSONTYPE
  3. Name
  4. ------------------------------------------------------------------------------
  5. PERSONNAME
  6. PERSONSEX
  7. PERSONBIRTH
  8. STUDENTNO
  9. STUDENTscore

(4)创建对象表

  1. CREATETABLEstudentOFStudentType;

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

  1. INSERTINTOstudentVALUES(''Rose'',''nv'',to_date(''1983-05-02'',''yyyy-mm-dd''),1001,98);

(6) 查询数据

  1. sql>SELECT*FROMstudent;
  2. PERSONNAMEPEPERSONBIRSTUDENTNOSTUDENTscore
  3. -------------------------------------------
  4. Rosenv02-MAY-83100198

二、可变数组

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

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

  1. CREATEORREPLACETYPEMingXiTypeASOBJECT
  2. (
  3. GoodIDvarchar2(20),
  4. InCountint,
  5. ProviderIDvarchar(20)
  6. );

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

  1. CREATEORREPLACETYPEarrMingXiTypeASVARRAY(100)OFMingXiType;

(3)创建一个主表

  1. CREATETABLEInStockOrder
  2. (
  3. OrderIDvarchar(15)NotNullPrimaryKey,
  4. InDatedate,
  5. OperatorIDvarchar(15),
  6. MingXiarrMingXiType
  7. );

2、操作可变数组

(1)插入数据

  1. INSERTINTOInStockOrder
  2. VALUES(''200710110001'',TO_DATE(''2007-10-11'',''YYYY-MM-DD''),''007'',
  3. arrMingXiType(MingXiType(''G001'',100,''1001''),
  4. MingXiType(''G002'',888,''1002''))
  5. );

(2)查询数据

  1. sql>SELECT*FROMInStockOrder;
  2. ORDERIDINDATEOPERATORID
  3. ---------------------------------------
  4. MINGXI(GOODID,INCOUNT,PROVIDERID)
  5. ----------------------------------------------------------------------
  6. 20071011000111-OCT-07007
  7. ARRMINGXITYPE(MINGXITYPE(''G001'',MINGXITYPE(''G002'',''1002'')

(3)使用Table()函数

  1. sql>SELECT*FROMTable(SELECTt.MingXiFROMInStockOrdert
  2. WHEREt.OrderID=''200710110001'');
  3. GOODIDINCOUNTPROVIDERID
  4. --------------------------------------------------
  5. G0011001001
  6. G0028881002

(4)修改数据

  1. UPDATEInStockOrder
  2. SETMingXi=arrMingXiType(MingXiType(''G001'',200,
  3. MingXiType(''G002'',8888,''1002''))
  4. WHEREOrderID=''200710110001''

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

三、嵌套表

1、创建嵌套表

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

  1. CREATEORREPLACETYPEMingXiTypeASOBJECT
  2. (
  3. GoodIDvarchar2(20),
  4. ProviderIDvarchar(20)
  5. )notfinal;

(2)创建嵌套表类型

  1. CREATEORREPLACETYPEnestMingXiTypeASTABLEOFMingXiType;

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

  1. CREATETABLEInStockTable
  2. (
  3. OrderIDvarchar(15)NotNullPrimaryKey,
  4. MingXinestMingXiType
  5. )NestedTableMingXiSTOREASMingXiTable;

2、操作嵌套表

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

  1. INSERTINTOInStockTable
  2. VALUES(''20071012001'',TO_DATE(''2007-10-12'',
  3. nestMingXiType(MingXiType(''G003'',666,
  4. MingXiType(''G004'',''1002''),
  5. MingXiType(''G005'',''1003''))
  6. );

(2)查询数据

  1. sql>SELECT*FROMInStockTable;
  2. ORDERIDINDATEOPERATORID
  3. ---------------------------------------
  4. MINGXI(GOODID,PROVIDERID)
  5. ----------------------------------------------------------------------------------------------------
  6. 2007101200112-OCT-07007
  7. NESTMINGXITYPE(MINGXITYPE(''G003'',MINGXITYPE(''G004'',MINGXITYPE(''G005'',''1003'')

(3)使用Table()函数

  1. sql>SELECT*FROMTable(SELECTT.MingXiFROMInStockTablet
  2. WHEREOrderID=''20071012001'')
  3. GOODIDINCOUNTPROVIDERID
  4. --------------------------------------------------
  5. G0036661001
  6. G0048881002
  7. G00588881003

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

  1. UPDATETable(SELECTt.MingXiFROMInStockTabletWHEREOrderID=''20071012001'')tt
  2. SETtt.InCount=1666WHEREtt.GoodID=''G003'';

(5)删除表中数据

  1. DELETETable(SELECTt.MingXiFROMInStockTabletWHEREOrderID=''20071012001'')tt
  2. WHEREtt.GoodID=''G003''

四、对象表

1、创建对象表

  1. CREATETABLEObjectTableOFMingXiType;

2、向表中插入数据

  1. INSERTINTOObjectTableVALUES(''G001'',500,''P005'');
  2. INSERTINTOObjectTableVALUES(''G002'',1000,''P008'');

3、查询对象表中的记录

  1. --A直接查询
  2. sql>SELECT*FROMObjectTable;
  3. GOODIDINCOUNTPROVIDERID
  4. ---------------------------------------------
  5. G001500P005
  6. G0021000P008
  7. --B用VALUE()函数查询
  8. sql>SELECTVALUE(O)FROMObjectTableO;
  9. VALUE(O)(GOODID,PROVIDERID)
  10. ------------------------------------------
  11. MINGXITYPE(''G001'',''P005'')
  12. MINGXITYPE(''G002'',''P008'')

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

  1. --AREF操作符引用行对象
  2. sql>SELECTREF(t)FROMObjectTablet;
  3. REF(T)
  4. --------------------------------------------------------------------------------
  5. 0000280209771F103ED34842478A9C439CDAEFEF6324B0ACF849F14BD7A8B52F4B0297D1C90040A9
  6. 5A0000
  7. 0000280209A2D3359E0F0C44B3AF652B944F8823F524B0ACF849F14BD7A8B52F4B0297D1C90040A9
  8. 5A0001
  9. --B将OID用于创建外键
  10. CREATETABLECustomer
  11. (CustomerIDvarchar(10)PRIMARYKEY,
  12. CustomerNamevarchar(20),
  13. CustomerGoodsREFMingXiTypeSCOPEISObjectTable,--引用MingXiType外键,关联的是OID的值
  14. CustomerAddressvarchar(20)
  15. );
  16. --C向Customer表中插入数据,此表将从上面创建的对象表中引用数据
  17. INSERTINTOCustomerSELECT''007'',''Yuanhy'',REF(O),''France''
  18. FROMObjectTableO
  19. WHEREGoodID=''G001'';
  20. --D查询Customer表
  21. sql>SELECT*FROMCustomer;
  22. CUSTOMERIDCUSTOMERNAME
  23. ------------------------------
  24. CUSTOMERGOODS
  25. -----------------------------------------------------------------------------
  26. CUSTOMERADDRESS
  27. --------------------
  28. 007Yuanhy
  29. 0000220208771F103ED34842478A9C439CDAEFEF6324B0ACF849F14BD7A8B52F4B0297D1C9
  30. France
  31. --E用DEREF操作符返回对象的值
  32. sql>SELECTCustomerID,CustomerName,DEREF(t.CustomerGoods),CustomerAddress
  33. 2FROMCustomert;
  34. CUSTOMERIDCUSTOMERNAME
  35. ------------------------------
  36. DEREF(T.CUSTOMERGOODS)(GOODID,PROVIDERID)
  37. ----------------------------------------------------------------------------
  38. CUSTOMERADDRESS
  39. --------------------
  40. 007Yuanhy
  41. MINGXITYPE(''G001'',''P005'')
  42. France

五、对象视图

将关系表化装成对象表

1、 创建对象视图

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

  1. CREATEORREPLACETYPEdepttypeASOBJECT
  2. (
  3. deptidnumber(10),
  4. deptnamevarchar(30),
  5. locnumber(10)
  6. );

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

  1. CREATEVIEWdeptviewOFdepttypeWITHOBJECTOID(deptid)AS
  2. SELECTdepartment_id,department_name,location_idFROMdept;

C 查询视图

  1. sql>SELECT*FROMdeptview;
  2. DEPTIDDEPTNAMELOC
  3. --------------------------------------------------
  4. 10Administration1700
  5. 20Marketing1800
  6. 30Purchasing1700
  7. 40HumanResources2400
  8. 50Shipping1500
  9. 60IT1400
  10. 70PublicRelations2700
  11. sql>selectref(t)fromdeptviewt;
  12. REF(T)
  13. ----------------------------------------------------------------------------------------------------
  14. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  15. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  16. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  17. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  18. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  19. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  20. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE

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

  1. CREATEVIEWempviewASSELECTMAKE_REF(deptview,department_id)deptOID,employee_id,
  2. first_name,last_nameFROMemp;

查询对象视图empview

  1. sql>SELECT*FROMempview;
  2. DEPTOID
  3. ----------------------------------------------------------------------------------------------------
  4. EMPLOYEE_IDFIRST_NAMELAST_NAME
  5. --------------------------------------------------------
  6. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  7. 100StevenKing
  8. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  9. 101NeenaKochhar
  10. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  11. 102LexDeHaan
  12. 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
  13. 103AlexanderHunold

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'',''测试''),这是个默认的构造函数

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

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

  注意:不能写成:SELECT * FROMSTUDENTS 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'',TO_DATE(''20060601'',''对象类型表'');

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

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

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

  对象类型表在: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) RETURNreturn_type,...

)

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

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

  1. CREATETYPEBODYtype_nameAS
  2. MEMBERFUNCTIONmethod_nameRETURNreturn_type{AS|IS}
  3. variabledeclareations..
  4. BEGIN
  5. CODE..
  6. RETURNreturn_value;
  7. END;//ENDMEMBERFUNCTION
  8. ...
  9. END;//ENDTYPEBODY
  10.  -- 如下所示:
  11. --
  12. CREATETYPEHUMANASOBJECT(
  13. NAMEVARCHAR2(20),
  14. SEXVARCHAR2(1),--F:FEMALEM:MALE
  15. BIRTHDAYDATE,
  16. NOTEVARCHAR2(300),
  17. MEMBERFUNCTIONGET_AGERETURNNUMBER
  18. )
  19. --BODY
  20. CREATETYPEBODYHUMANAS
  21. MEMBERFUNCTIONGET_AGERETURNNUMBERAS
  22. V_MONTHSNUMBER;
  23. BEGIN
  24. SELECTFLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12)INTOV_MONTHSFROMDUAL;
  25. RETURNV_MONTHS;
  26. END;
  27. 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'',TO_DATE(''19830714'',''过程'');

AGE := AA.GET_AGE();

DBMS_OUTPUT.PUT_LINE(AGE);

END;

  映射方法

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

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

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

MAP MEMBER FUNCTION function_name RETURNreturn_type

  修改前文提到的HUMAN类型:

--映射方法 MAP

  1. CREATETYPEHUMANASOBJECT(
  2. NAMEVARCHAR2(20),
  3. SEXVARCHAR2(1),--F:FEMALEM:MALE
  4. BIRTHDAYDATE,--注册日期 
  5. REGISTERDAYDATE,
  6. MEMBERFUNCTIONGET_AGERETURNNUMBER,
  7. MAPMEMBERFUNCTIONGET_GRADERETURNNUMBER
  8. )
  9. CREATETYPEBODYHUMANAS
  10. -----------------------
  11. MEMBERFUNCTIONGET_AGERETURNNUMBERAS
  12. V_MONTHSNUMBER;
  13. BEGIN
  14. SELECTFLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12)INTOV_MONTHSFROMDUAL;
  15. RETURNV_MONTHS;
  16. END;
  17. ------------------------
  18. MAPMEMBERFUNCTIONGET_GRADERETURNNUMBERAS
  19. BEGIN
  20. RETURNMONTHS_BETWEEN(SYSDATE,BIRTHDAY);
  21. END;
  22. END;

插入数据:

  1. INSERTINTOSTUDENTS(STUDENT)VALUES(HUMAN(''xling'',''M'',TO_DATE(''19830714'',''YYYYMMDD''),TO_DATE(''20020915'',''测试MAP方法''));
  2. INSERTINTOSTUDENTS(STUDENT)VALUES(HUMAN(''fairy'',TO_DATE(''20010915'',''测试MAP方法''));
  3. INSERTINTOSTUDENTS(STUDENT)VALUES(HUMAN(''snow'',''测试MAP方法''));

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

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

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

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

  1. SELECTS.STUDENT.NAME,S.STUDENT.GET_GRADE()FROMSTUDENTSSWHERES.STUDENT.GET_GRADE()>50
  2. SELECTS.STUDENT.NAME,S.STUDENT.GET_GRADE()FROMSTUDENTSSWHERESTUDENT>HUMAN(NULL,NULL,TO_DATE(''20020101'',NULL);

  排序方法

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

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

--映射方法 MAP

  1. CREATETYPEHUMANASOBJECT(
  2. NAMEVARCHAR2(20),
  3. REGISTERDAYDATE,
  4. ORDERMEMBERFUNCTIONMATCH(I_STUDENTINHUMAN)RETURNNUMBER
  5. )
  6. CREATETYPEBODYHUMANAS
  7. -----------------------
  8. MEMBERFUNCTIONGET_AGERETURNNUMBERAS
  9. V_MONTHSNUMBER;
  10. BEGIN
  11. SELECTFLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12)INTOV_MONTHSFROMDUAL;
  12. RETURNV_MONTHS;
  13. END;
  14. ------------------------
  15. ORDERMEMBERFUNCTIONMATCH(I_STUDENTINHUMAN)RETURNNUMBERAS
  16. BEGIN
  17. RETURNREGISTERDAY-I_STUDENT.REGISTERDAY;
  18. END;
  19. END;

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

  1. SETSERVEROUTPUTON
  2. DECLARE
  3. S1HUMAN;
  4. S2HUMAN;
  5. BEGIN
  6. S1:=HUMAN(''xling'',NULL);
  7. S2:=HUMAN(''snow'',NULL);
  8. IFS1>S2THEN
  9. DBMS_OUTPUT.PUT_LINE(S1.NAME);
  10. ELSIFS1<S2THEN
  11. DBMS_OUTPUT.PUT_LINE(S2.NAME);
  12. ELSE
  13. DBMS_OUTPUT.PUT_LINE(''EQUAL'');
  14. ENDIF;
  15. END;

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

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

实例:

(1)定义对象类型:TYPE sales_country_t

CREATE TYPE sales_country_t AS OBJECT (

  YEAR             VARCHAR2 (4),country          CHAR (2),sum_amount_sold   NUMBER

);

(2)定义表类型:TYPE SUM_SALES_COUNTRY_T_TAB

CREATE TYPE sum_sales_country_t_tab AS TABLEOF sales_country_t;

(3)定义对象类型:TYPE sales_gender_t

CREATE TYPE sales_gender_t AS OBJECT (

  YEAR             VARCHAR2 (4),country_id       CHAR (2),cust_gender       CHAR(1),sum_amount_sold   NUMBER

);

(4)定义表类型:TYPE SUM_SALES_GENDER_T_TAB

CREATE TYPE sum_sales_gender_t_tab AS TABLEOF sales_gender_t;

(5) 也可以使用基本类型定义 表类型比如:

create or replace typetest_tab_type as table of varchar2(4000);

varchar2(4000) 是一个资本类型,这样相当于定义的表中只有一个字段varchar2(4000)

用法:

  1. TYPEsales_country_t_recISRECORD(
  2. YEARVARCHAR(4),
  3. countryCHAR(2),
  4. sum_amount_soldNUMBER
  5. );
  6. v_sales_country_t_recsales_country_t_rec;

引用:

  1. v_sales_country_t_rec.year:='ssss';
  2. v_sales_country_t_rec.country:='a';
  3. v_sales_country_t_rec.sum_amount_sold:=2;

1 首先创建一个数据类型

create type t_air  as object(id int,name varchar(20));

2 创建表

create table aaa(id int,persont_air);

3 插入数据

insert into aaa values(1,t_air(1,'23sdf'));

4 查询classPlace

select a.id,a.persion.id,a.person.name fromaaa a;

t_air(1,'23sdf') 使用这个方式创建一个自定义类型t_air的对象.

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

三:下面简单的枚举下常用的几种自定义类型。

1、子类型。
这种类型最简单,类似类型的一个别名,主要是为了对常用的一些类型简单化,它基于原始的某个类型。如:
有些应用会经常用到一些货币类型:number(16,2)。如果在全局范围各自定义这种类型,一旦需要修改该类型的精度,则需要一个个地修改

@H_890_403@那如何实现定义的全局化呢?于是就引出了子类型:

subtype cc_num is number(16,2);

这样就很方便地解决了上述的麻烦。

整理:

http://www.jb51.cc/article/p-bejdqwfe-bhc.html

http://www.jb51.cc/article/p-yldnglfm-y.html

http://blog.itpub.net/12932950/viewspace-662514

http://psoug.org/reference/type.html

猜你在找的Oracle相关文章