注:为了更加清晰的看清有些没有格式的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:如何创建和使用记录?
①创建记录类型
语法:
- TYPE记录名ISRECORD
- (
- filed1type1[NOTNULL][:=eXPr1],
- .......,
- filedNtypen[NOTNULL][:=exprn]
- )
其中,filed1是标量的名字。
②声明记录类型变量:
记录类型变量名 记录类型
③填充记录。
④访问记录成员
记录类型变量名.filed1
.........
记录类型变量名.filedN
注意:
表字段类型修改后,还需要修改记录字段类型,有时候可能会忘记,从而出现错误。对于记录内每个字段(filed1...),可以指定也可以使用%TYPE和%ROWTYPE动态指定记录字段类型。好处是表字段发生变化,记录字段自动改变。但是,由于每次执行前,遇到%TYPR或%ROWTYPE,数据库系统都会去查看对应表字段类型,会造成一定的数据库开销,如果系统中大量使用记录类型,则对性能会有一定影响。另外如果删除了某一字段,而自定义记录中使用了该字段,也会有可能忘记删除该字段。对数据库负荷偏低的系统,性能问题一般可以不重点关注,但是对于高负荷数据库服务器,各个环节都要考虑性能问题,每处节省一点出来,性能整体就有很大提高。
语法:
- TYPE记录名ISRECORD
- (
- filed1table.Filed%Type[NOTNULL][:=eXPr1],
- filed2table.Filed%Type[NOTNULL][:=eXPr1],
- .......,
- filedntable.Filed%Type[NOTNULL][:=exprn]
- );
例子:记录可以整体赋值
- /*connscott/tiger
- CreateTableempaAsSelect*Fromemp;
- */
- Declare
- TypeEmpTypeisRecord(
- EMPNOnumber(4),
- ENAMEvarchar2(10),
- JOBvarchar2(15),
- SALnumber(7,2),
- DEPTNOnumber(2)
- );
- EmpRec1EmpType;
- EmpRec2EmpType;
- Begin
- EmpRec1.Empno:=7369;
- EmpRec1.Ename:='SMITH';
- EmpRec1.Job:='CLERK';
- EmpRec1.Sal:=800;
- EmpRec1.Deptno:=10;
- EmpRec2:=EmpRec1;
- DBMS_output.put_line(EmpRec2.empno);
- End;
- Declare
- TypeEmpTypeisRecord(
- EMPNOnumber(4),
- ENAMEvarchar2(10),
- JOBvarchar2(15),
- SALnumber(7,
- DEPTNOnumber(2)
- );
- EmpRec1EmpType;
- EmpRec2EmpType;
- Begin
- EmpRec1.Empno:=7369;
- EmpRec1.Ename:='SMITH';
- EmpRec1.Job:='CLERK';
- EmpRec1.Sal:=800;
- EmpRec1.Deptno:=10;
- ifEmpRec1.sal<EmpRec2.salthen
- DBMS_output.put_line('XiaoXiaoXiao');
- endif;
- End;
- Declare
- TypeEmpTypeisRecord(
- EMPNOnumber(4),
- DEPTNOnumber(2)
- );
- EmpRecEmpType;
- Begin
- ifEmpRec.enameisnullthen
- DBMS_output.put_line('KongKongKong');
- endif;
- End;
- /*connscott/tiger
- CreateTableempaAsSelect*Fromemp;
- */
- DECLARE
- TypeMyRecTypeIsRecord
- (
- RENOEMPA.EMPNO%Type,
- RENAMEEMPA.ENAME%Type,
- RJOBEMPA.JOB%Type
- );
- EmpRecMyRecType;
- Begin
- SelectEMPNO,ENAME,JOBInToEmpRecFromempaWhereempa.EMPNO='7369';
- IfEmpRec.RJOB='CLERK'Then
- DBMS_OUTPUT.PUT_LINE('Name:'||EmpRec.RENAME);
- EndIf;
- End;
- DECLARE
- TypeMyRecTypeIsRecord
- (
- RENOEMPA.EMPNO%Type,
- RENAMEEMPA.ENAME%Type,
- RJOBEMPA.JOB%Type
- );
- EmpRecMyRecType;
- vJobEMPA.JOB%Type;
- Begin
- SelectEMPNO,JOBInToEmpRecFromempaWhereempa.EMPNO='7369';
- DBMS_OUTPUT.PUT_LINE('MyRecType.RJOB:'||EmpRec.RJOB);
- EmpRec.RJOB:='修改值后';
- DBMS_OUTPUT.PUT_LINE('MyRecType.RJOB:'||EmpRec.RJOB);
- SelectJOBInTovJobfromempaWhereempa.EMPNO=EmpRec.RENO;
- DBMS_OUTPUT.PUT_LINE('EMPA.JOB:'||vJob);
- End;
- /
3.4:使用记录向表中插入数据?
根据表结构合理安排记录字段。比如主外键。
如果用记录(RECORD)插入数据,那么只能使用记录成员;如果用%ROWTYPE插入数据,可以直接使用%ROWTYPE。
例子:使用记录成员向表中插入数据
- DECLARE
- TypeMyRecTypeIsRecord
- (
- RENOEMPA.EMPNO%Type,
- RENAMEVARCHAR2(10),
- RJOBEMPA.JOB%Type
- );
- EmpRecMyRecType;
- Begin
- SelectEMPNO,JOBInToEmpRecFromempaWhereempa.EMPNO='7369';
- DBMS_OUTPUT.PUT_LINE(EmpRec.RENO||''||EmpRec.RENAME||''||EmpRec.RJOB);
- EmpRec.RENO:=1001;
- EmpRec.RENAME:='杰克';
- EmpRec.RJOB:='办事员';
- InsertInToempa(EMPNO,JOB)Values(EmpRec.RENO,EmpRec.RENAME,EmpRec.RJOB);
- SelectEMPNO,JOBInToEmpRecFromempaWhereempa.EMPNO='1001';
- DBMS_OUTPUT.PUT_LINE(EmpRec.RENO||''||EmpRec.RENAME||''||EmpRec.RJOB);
- End;
3.5:使用记录更新数据?
如果用记录(RECORD)更新数据,那么只能使用记录成员;
如果用%ROWTYPE更新数据,可以直接使用%ROWTYPE。
例子:使用%ROWTYPE向表中插入数据
- DECLARE
- vEmpempa%RowType;
- Begin
- Select*InTovEmpFromempaWhereempa.EMPNO='7369';
- UpDateempaSetROW=vEmpWhereEMPNO=1001;
- End;
四: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.
- declare
- typet_tableistableofvarchar2(10)indexbyBINARY_integer;
- MyTabt_table;
- begin
- MyTab(1):='A';
- MyTab(2):='B';
- MyTab(3):='C';
- DBMS_OUTPUT.PUT_LINE('Firstindex:'||''||mytab(1)||'');
- end;
- --
- DECLARE
- TYPEt_StudentTableISTABLEOFstudents%ROWTYPEINDEXBYBINARY_INTEGER;
- v_Studentst_StudentTable;
- BEGIN
- SELECT*INTOv_Students(1100)
- FROMstudents
- WHEREid=1100;
- DBMS_OUTPUT.PUT_LINE(v_Students(1100).OUUSRNM);
- END;
- /*connscott/tiger
- Createtableempaasselect*fromemp;
- */
- --例子:
- Declare
- TypeRecTypeIsRecord
- (
- rnoempa.empno%type,
- rnameempa.ename%type,
- rsalempa.sal%type
- );
- TypeTabTypeIsTableOfRecTypeIndexByBinary_Integer;
- MyTabTabType;
- vNNumber;
- Begin
- --填充
- vN:=1;
- ForvarRIn(Select*FromempaOrderByempnoASC)
- Loop
- MyTab(vN).rno:=varR.empno;
- MyTab(vN).rname:=varR.ename;
- MyTab(vN).rsal:=varR.sal;
- vN:=vN+1;
- EndLoop;
- --访问
- vN:=MyTab.First;
- ForvarRInvN..MyTab.count
- Loop
- DBMS_OUTPUT.PUT_LINE(vN||''||MyTab(vN).rno||''||MyTab(vN).rname||''||MyTab(vN).rsal);
- vN:=MyTab.Next(vN);
- EndLoop;
- 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”时:
- declare
- typenumbersistableofnumber;
- nnumbers:=numbers();
- begin
- n.extend;
- n(1):=2;
- n.extend;
- n(2):=3;
- foriin1..n.countloop
- dbms_output.put_line(n(i));
- endloop;
- end;
- --输出:2,3
- declare
- typenumbersistableofnumberindexbybinary_integer;
- nnumbers;
- begin
- n(1):=2;
- n(2):=3;
- foriin1..n.countloop
- dbms_output.put_line(n(i));
- endloop;
- end;
五:create type 用法
5.1:定义
概念
方法:是在对象类型说明中用关键字 MEMBER 声明的子程序
与数据包程序相似,大多数方法有两个部分
- CREATE[ORREPLACE]TYPE<typename>ASOBJECT
- (attribute1datatype,
- :
- attributeNdatatype
- MEMBERPROCEDURE<methodname>(parameter,mode,datatype),
- MEMBERFUNCTION<methodname>(parameter,datatype)RETURNdatatype,
- PRAGMARESTRICT_REFERENCES(<methodname>,WNDS/RNDS/WNPS/RNPS)
- );
说明:PRAGMA RESTRICT_REFERENCES指定MEMBER方法按以下模式之一 操作:
–WNPS (不能写入数据包状态) 不能更改数据包变量的值
–RNPS (不能读出数据包状态) 不能引用数据包变量的值
例:
- createorreplacetypeFLIGHT_SCH_TYPEasobject
- (FLIGHTNOVARCHAR2(4),AIRBUSNOVARCHAR2(5),
- ROUTE_CODEVARCHAR2(7),DEPRT_TIMEVARCHAR2(10),
- JOURNEY_HURSVARCHAR2(10),FLIGHT_DAY1NUMBER(1),
- FLIGHT_DAY2NUMBER(1),
- MemberfunctionDAYS_FN(FLIGHT_DAY1innumber)returnvarchar2,
- Pragmarestrict_references(DAYS_FN,WNDS));
创建对象类型方法主体
- CREATE[ORREPLACE]TYPEBODY<typename>ASMEMBERFUNCTION<methodname>(parameterdataype)RETURN<datatype>IS<PL/sql_block>;
- MEMBERPROCEDURE<methodname>(parameterdatatype);
- END;
例:
- createorreplacetypebodyFLIGHT_SCH_TYPEas
- memberfunctionDAYS_FN(FLIGHT_DAY1innumber)returnvarchar2
- is
- disp_dayvarchar2(20);
- begin
- ifflight_day1=1then
- disp_day:='Sunday';
- elsifflight_day1=2then
- disp_day:='Monday';
- elsifflight_day1=3then
- disp_day:='Tuesday';
- elsifflight_day1=4then
- disp_day:='Wednesday';
- elsifflight_day1=5then
- disp_day:='Thursday';
- elsifflight_day1=6then
- disp_day:='Friday';
- elsifflight_day1=7then
- disp_day:='Saturday';
- endif;
- returndisp_day;
- end;
- end;
A. 创建基于对象的表语法:
create table <表名> of <对象类型>:此表具有该类型和member方法的所有属性,我们不能通过DBA STUdio的表数据编辑器来编辑数据。
例:
- createtableFLIGHT_SCH_TABofFLIGHT_SCH_TYPE
- insertintoFLIGHT_SCH_TABvalues('SL36','AB02','SAN-LOU','5','13:30',3,6);
B.访问对象表中的MEMBER语法:
SELECT <columnname>,<aliasname>.<methodname(parameters)> FROM <tablename> <aliasname>;
例:
- 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)
例:
- insertintoFLIGHT_SCH_TABSvalues(FLIGHT_SCH_TYPE('SL36',6),'DESC1');
D.访问关系表中的Member方法此处的关系表:指表中有字段为对象类型
SELECT <columnname>,<aliasname>.<columnname>.<methodname (parameters)>FROM <tablename> <aliasname>;
例:
- 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>
例:
- 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运算符的外键列的关系
可按如下步骤关联两个表
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
简单用法:
- createorreplacetypetyp_calendarasobject(
- 年varchar2(8),
- 月varchar2(8),
- 星期日varchar2(8),
- 星期一varchar2(8),
- 星期二varchar2(8),
- 星期三varchar2(8),
- 星期四varchar2(8),
- 星期五varchar2(8),
- 星期六varchar2(8),
- 本月最后一日varchar2(2)
- );
- --这种类型可以在表结构定义的时候使用:
- createtabletcalendaroftyp_calendar;
- --插入数据测试:
- sql>insertintotcalendar
- 2selecttyp_calendar('2010','05','1','2','3','4','6','7','31')fromdual
- 3/
- --注意:插入的数据需要用typ_calendar进行转换。
- 1rowinserted
- --查看结果
- sql>select*fromtcalendar;
- 年月星期日星期一星期二星期三星期四星期五星期六本月最后一日
- ------------------------------------------------------------------------------------
- 201005123456731
复杂用法:
一、抽象数据类型
1、创建类型
--地址类型
- CREATEORREPLACETYPEAddressTypeASOBJECT
- (
- Countryvarchar2(15),
- Cityvarchar2(20),
- Streetvarchar2(30)
- );
2、类型嵌套
--创建基于前一个类型的新的抽象数据类型:巨星类型
- CREATEORREPLACETYPESuperStarTypeASOBJECT
- (
- StarNamevarchar2(30),
- AddressAddressType
- );
3、基于抽象类型创建关系表
- CREATETABLESuperStar
- (
- StarIDvarchar(10),
- StarSuperStarType
- );
4、基于抽象类型创建对象表
- CREATETABLESuperStarObjofSuperStarType;
5、使用构造方法在表中插入记录
- INSERTINTOSuperStarVALUES(''001'',SuperStarType(''Zidane'',AddressType(''France'',''Paris'',''PeopleStreetNO.1'')));
6、查询表中记录
- (1)sql>SELECT*FROMSuperStar;
- STARID
- ----------
- STAR(STARNAME,ADDRESS(COUNTRY,CITY,STREET))
- --------------------------------------------------------------------------------
- 001
- SUPERSTARTYPE(''Zidane'',ADDRESSTYPE(''France'',''PeopleStreetNO.1''))
- (2)
- SELECTs.StarID,s.Star.StarName,s.Star.Address.Country,s.Star.Address.City,s.Star.Address.StreetFROMSuperStars
- STARIDSTAR.STARNAMESTAR.ADDRESS.COSTAR.ADDRESS.CITYSTAR.ADDRESS.STREET
- ------------------------------------------------------------------------------------------------
- 001ZidaneFranceParisPeopleStreetNO.1
7、抽象数据类型的继承
(1)创建一个类型
- CREATEORREPLACETYPEPersonTypeASOBJECT
- (
- PersonNamevarchar(10),
- PersonSexvarchar(2),
- PersonBirthdate
- )notfinal;
(2)派生一个类型
- CREATEORREPLACETYPEStudentTypeUNDERPersonType
- (
- StudentNOint,
- Studentscoreint
- );
(3)查看数据字典
(4)创建对象表
- CREATETABLEstudentOFStudentType;
(5)向对象表中插入数据
- INSERTINTOstudentVALUES(''Rose'',''nv'',to_date(''1983-05-02'',''yyyy-mm-dd''),1001,98);
(6) 查询数据
二、可变数组
1、创建带有可变数组的表
(1)创建可变数组的基类型
- CREATEORREPLACETYPEMingXiTypeASOBJECT
- (
- GoodIDvarchar2(20),
- InCountint,
- ProviderIDvarchar(20)
- );
(2)创建嵌套项类型的可变数组
- CREATEORREPLACETYPEarrMingXiTypeASVARRAY(100)OFMingXiType;
(3)创建一个主表
- CREATETABLEInStockOrder
- (
- OrderIDvarchar(15)NotNullPrimaryKey,
- InDatedate,
- OperatorIDvarchar(15),
- MingXiarrMingXiType
- );
2、操作可变数组
(1)插入数据
- INSERTINTOInStockOrder
- VALUES(''200710110001'',TO_DATE(''2007-10-11'',''YYYY-MM-DD''),''007'',
- arrMingXiType(MingXiType(''G001'',100,''1001''),
- MingXiType(''G002'',888,''1002''))
- );
(2)查询数据
- sql>SELECT*FROMInStockOrder;
- ORDERIDINDATEOPERATORID
- ---------------------------------------
- MINGXI(GOODID,INCOUNT,PROVIDERID)
- ----------------------------------------------------------------------
- 20071011000111-OCT-07007
- ARRMINGXITYPE(MINGXITYPE(''G001'',MINGXITYPE(''G002'',''1002'')
(3)使用Table()函数
- sql>SELECT*FROMTable(SELECTt.MingXiFROMInStockOrdert
- WHEREt.OrderID=''200710110001'');
- GOODIDINCOUNTPROVIDERID
- --------------------------------------------------
- G0011001001
- G0028881002
(4)修改数据
- UPDATEInStockOrder
- SETMingXi=arrMingXiType(MingXiType(''G001'',200,
- MingXiType(''G002'',8888,''1002''))
- WHEREOrderID=''200710110001''
注意:不能更新VARRAY中的单个元素,必须更新整个VARRAY
三、嵌套表
1、创建嵌套表
(1)创建嵌套表的基类型
- CREATEORREPLACETYPEMingXiTypeASOBJECT
- (
- GoodIDvarchar2(20),
- ProviderIDvarchar(20)
- )notfinal;
(2)创建嵌套表类型
- CREATEORREPLACETYPEnestMingXiTypeASTABLEOFMingXiType;
(3)创建主表,其中一列是嵌套表类型
- CREATETABLEInStockTable
- (
- OrderIDvarchar(15)NotNullPrimaryKey,
- MingXinestMingXiType
- )NestedTableMingXiSTOREASMingXiTable;
2、操作嵌套表
(1)向嵌套表中插入记录
- INSERTINTOInStockTable
- VALUES(''20071012001'',TO_DATE(''2007-10-12'',
- nestMingXiType(MingXiType(''G003'',666,
- MingXiType(''G004'',''1002''),
- MingXiType(''G005'',''1003''))
- );
(2)查询数据
- sql>SELECT*FROMInStockTable;
- ORDERIDINDATEOPERATORID
- ---------------------------------------
- MINGXI(GOODID,PROVIDERID)
- ----------------------------------------------------------------------------------------------------
- 2007101200112-OCT-07007
- NESTMINGXITYPE(MINGXITYPE(''G003'',MINGXITYPE(''G004'',MINGXITYPE(''G005'',''1003'')
(3)使用Table()函数
- sql>SELECT*FROMTable(SELECTT.MingXiFROMInStockTablet
- WHEREOrderID=''20071012001'')
- GOODIDINCOUNTPROVIDERID
- --------------------------------------------------
- G0036661001
- G0048881002
- G00588881003
(4)更新嵌套表中的数据
- UPDATETable(SELECTt.MingXiFROMInStockTabletWHEREOrderID=''20071012001'')tt
- SETtt.InCount=1666WHEREtt.GoodID=''G003'';
(5)删除表中数据
- DELETETable(SELECTt.MingXiFROMInStockTabletWHEREOrderID=''20071012001'')tt
- WHEREtt.GoodID=''G003''
四、对象表
1、创建对象表
- CREATETABLEObjectTableOFMingXiType;
2、向表中插入数据
- INSERTINTOObjectTableVALUES(''G001'',500,''P005'');
- INSERTINTOObjectTableVALUES(''G002'',1000,''P008'');
3、查询对象表中的记录
- --A直接查询
- sql>SELECT*FROMObjectTable;
- GOODIDINCOUNTPROVIDERID
- ---------------------------------------------
- G001500P005
- G0021000P008
- --B用VALUE()函数查询
- sql>SELECTVALUE(O)FROMObjectTableO;
- VALUE(O)(GOODID,PROVIDERID)
- ------------------------------------------
- MINGXITYPE(''G001'',''P005'')
- MINGXITYPE(''G002'',''P008'')
4、查看对象标志符(OID)
- --AREF操作符引用行对象
- sql>SELECTREF(t)FROMObjectTablet;
- REF(T)
- --------------------------------------------------------------------------------
- 0000280209771F103ED34842478A9C439CDAEFEF6324B0ACF849F14BD7A8B52F4B0297D1C90040A9
- 5A0000
- 0000280209A2D3359E0F0C44B3AF652B944F8823F524B0ACF849F14BD7A8B52F4B0297D1C90040A9
- 5A0001
- --B将OID用于创建外键
- CREATETABLECustomer
- (CustomerIDvarchar(10)PRIMARYKEY,
- CustomerNamevarchar(20),
- CustomerGoodsREFMingXiTypeSCOPEISObjectTable,--引用MingXiType外键,关联的是OID的值
- CustomerAddressvarchar(20)
- );
- --C向Customer表中插入数据,此表将从上面创建的对象表中引用数据
- INSERTINTOCustomerSELECT''007'',''Yuanhy'',REF(O),''France''
- FROMObjectTableO
- WHEREGoodID=''G001'';
- --D查询Customer表
- sql>SELECT*FROMCustomer;
- CUSTOMERIDCUSTOMERNAME
- ------------------------------
- CUSTOMERGOODS
- -----------------------------------------------------------------------------
- CUSTOMERADDRESS
- --------------------
- 007Yuanhy
- 0000220208771F103ED34842478A9C439CDAEFEF6324B0ACF849F14BD7A8B52F4B0297D1C9
- France
- --E用DEREF操作符返回对象的值
- sql>SELECTCustomerID,CustomerName,DEREF(t.CustomerGoods),CustomerAddress
- 2FROMCustomert;
- CUSTOMERIDCUSTOMERNAME
- ------------------------------
- DEREF(T.CUSTOMERGOODS)(GOODID,PROVIDERID)
- ----------------------------------------------------------------------------
- CUSTOMERADDRESS
- --------------------
- 007Yuanhy
- MINGXITYPE(''G001'',''P005'')
- France
五、对象视图
将关系表化装成对象表
1、 创建对象视图
A 创建基于关系表父表的对象类型
- CREATEORREPLACETYPEdepttypeASOBJECT
- (
- deptidnumber(10),
- deptnamevarchar(30),
- locnumber(10)
- );
B 创建基于关系表的对象视图
- CREATEVIEWdeptviewOFdepttypeWITHOBJECTOID(deptid)AS
- SELECTdepartment_id,department_name,location_idFROMdept;
C 查询视图
- sql>SELECT*FROMdeptview;
- DEPTIDDEPTNAMELOC
- --------------------------------------------------
- 10Administration1700
- 20Marketing1800
- 30Purchasing1700
- 40HumanResources2400
- 50Shipping1500
- 60IT1400
- 70PublicRelations2700
- sql>selectref(t)fromdeptviewt;
- REF(T)
- ----------------------------------------------------------------------------------------------------
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
2、创建引用视图(类似于关系表创建一个从表)
- CREATEVIEWempviewASSELECTMAKE_REF(deptview,department_id)deptOID,employee_id,
- first_name,last_nameFROMemp;
查询对象视图empview
- sql>SELECT*FROMempview;
- DEPTOID
- ----------------------------------------------------------------------------------------------------
- EMPLOYEE_IDFIRST_NAMELAST_NAME
- --------------------------------------------------------
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 100StevenKing
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 101NeenaKochhar
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 102LexDeHaan
- 00004A038A004667BAC3685B444520A60ED30027E8F25F0000001426010001000100290000000000090604002A00078401FE
- 103AlexanderHunold
创建对象类型与创建表很相似,只是实际上不为存储的数据分配空间:
不带方法的简单对象类型:
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:
- CREATETYPEBODYtype_nameAS
- MEMBERFUNCTIONmethod_nameRETURNreturn_type{AS|IS}
- variabledeclareations..
- BEGIN
- CODE..
- RETURNreturn_value;
- END;//ENDMEMBERFUNCTION
- ...
- END;//ENDTYPEBODY
- -- 如下所示:
- --
- CREATETYPEHUMANASOBJECT(
- NAMEVARCHAR2(20),
- SEXVARCHAR2(1),--F:FEMALEM:MALE
- BIRTHDAYDATE,
- NOTEVARCHAR2(300),
- MEMBERFUNCTIONGET_AGERETURNNUMBER
- )
- --BODY
- CREATETYPEBODYHUMANAS
- MEMBERFUNCTIONGET_AGERETURNNUMBERAS
- V_MONTHSNUMBER;
- BEGIN
- SELECTFLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12)INTOV_MONTHSFROMDUAL;
- RETURNV_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'',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
- CREATETYPEHUMANASOBJECT(
- NAMEVARCHAR2(20),
- SEXVARCHAR2(1),--F:FEMALEM:MALE
- BIRTHDAYDATE,--注册日期
- REGISTERDAYDATE,
- MEMBERFUNCTIONGET_AGERETURNNUMBER,
- MAPMEMBERFUNCTIONGET_GRADERETURNNUMBER
- )
- CREATETYPEBODYHUMANAS
- -----------------------
- MEMBERFUNCTIONGET_AGERETURNNUMBERAS
- V_MONTHSNUMBER;
- BEGIN
- SELECTFLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12)INTOV_MONTHSFROMDUAL;
- RETURNV_MONTHS;
- END;
- ------------------------
- MAPMEMBERFUNCTIONGET_GRADERETURNNUMBERAS
- BEGIN
- RETURNMONTHS_BETWEEN(SYSDATE,BIRTHDAY);
- END;
- END;
插入数据:
在执行上面的操作后,用下面这个SELECT语句可以看出映射方法的效果:
SELECT S.STUDENT.NAME,S.STUDENT.GET_GRADE()FROM STUDENTS S ORDER BY STUDENT
它是按MAP方法GET_GRADE()的值进行排序的.注意是ORDER BY STUDENT,在提起一次需要注意,一定要用表的别名,方法后的括号不能省略,即使没有参数.
如果想以MAP方法的结果为条件,可以如下:
- SELECTS.STUDENT.NAME,S.STUDENT.GET_GRADE()FROMSTUDENTSSWHERES.STUDENT.GET_GRADE()>50
- 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
- CREATETYPEHUMANASOBJECT(
- NAMEVARCHAR2(20),
- REGISTERDAYDATE,
- ORDERMEMBERFUNCTIONMATCH(I_STUDENTINHUMAN)RETURNNUMBER
- )
- CREATETYPEBODYHUMANAS
- -----------------------
- MEMBERFUNCTIONGET_AGERETURNNUMBERAS
- V_MONTHSNUMBER;
- BEGIN
- SELECTFLOOR(MONTHS_BETWEEN(SYSDATE,BIRTHDAY)/12)INTOV_MONTHSFROMDUAL;
- RETURNV_MONTHS;
- END;
- ------------------------
- ORDERMEMBERFUNCTIONMATCH(I_STUDENTINHUMAN)RETURNNUMBERAS
- BEGIN
- RETURNREGISTERDAY-I_STUDENT.REGISTERDAY;
- END;
- END;
注意:在声明的时候,ORDER方法的参数类型要和SELF的类型一致.
- SETSERVEROUTPUTON
- DECLARE
- S1HUMAN;
- S2HUMAN;
- BEGIN
- S1:=HUMAN(''xling'',NULL);
- S2:=HUMAN(''snow'',NULL);
- IFS1>S2THEN
- DBMS_OUTPUT.PUT_LINE(S1.NAME);
- ELSIFS1<S2THEN
- DBMS_OUTPUT.PUT_LINE(S2.NAME);
- ELSE
- DBMS_OUTPUT.PUT_LINE(''EQUAL'');
- ENDIF;
- 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)
用法:
- TYPEsales_country_t_recISRECORD(
- YEARVARCHAR(4),
- countryCHAR(2),
- sum_amount_soldNUMBER
- );
- v_sales_country_t_recsales_country_t_rec;
引用:
- v_sales_country_t_rec.year:='ssss';
- v_sales_country_t_rec.country:='a';
- 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)。如果在全局范围各自定义这种类型,一旦需要修改该类型的精度,则需要一个个地修改。
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