Oracle学习笔记李铁峰(2003-01-10)这篇笔记主要总结了机械工业出版社的《Oracle8PL/SQL程序设计》的主要语法和内置函数部分1第一章PL/SQL简介1.1块结构(Block)DECLARE--declarativesection/*声明部分,声明变量(variables)、类型(types)、游标(cursors)和局部子程序*/BEGIN--executablesection/*执行部分,放置过程性语句(proceduralstatement)*或SQL语句(SQLstatemnet)。*这是主体,是必须的。*/EXCTPTION--exceptionsection/*错误处理部分*/END;//“;”很关键,不要忘记1.2变量和类型(variablesandtypes)支持各种常用的数据库类型,还支持用户自定义类型,如表(table)、记录(record)。还支持对象类型。1.3注释(comment)Oracle的PL/SQL支持--和“/**/”的注释风格。2第二章PL/SQL基础2.1PL/SQL块匿名块(anonymous)动态生成,只执行一次。带名块(named)是带有标签的匿名块,动态生成,只执行一次。子程序(subprogram)是存储在数据库内部的过程、函数和包。可多次执行。触发器(trigger)是存储在数据库内部的带名块,可多次执行。由触发事件(triggeringevent)来触发。2.2词法单位(lexicalunit)包括标识符(identifier)、分界符(delimiter)、文字(literal)和注释(comment)2.2.1标识符(identifier)PL/SQL对大小写不敏感。最长30位。a)保留字(reservedword)或关键字(keyword),保留字单独使用时是保留的,但可以出现在其他标识符的内部。如:下面的用法是合法的,尽管“Date”是保留字。DECLAREv_BeginDateDate;b)引号标识符(quotedidentifier)如果想要标识符大小写敏感,如在标识符中出现空格这样的字符或使用一个保留字,那么必须使用引号标识符。如果想对含有名为“exception”的列的表进行查询:SELECTEXCEPTIONFROMTABLENAME2.2.2分界符(delimiter)+、-、*、/:加减乘除=、(or!=or^=or~=)、、、=、=:比较操作符(、):表达式分界符::绑定变量指示符;:语句终结符%:属性指示符.:组件选择符,:项目分隔符:引号标识符的分界符**:指数操作符@:数据库链接指示符:=:赋值操作符=:联结操作符(干什么的?)..:范围操作符||:字符串连接符、:标签分界符--,/**/:注释分界符space,tab,cr:空格、制表符、回车2.2.3文字(literal)字符型:以'为分隔符,如'1234'数字型:指数表示,如1.345E+12,E(e)表示指数(exponent)布尔型:TRUE,FALSE,NULL2.2.4注释(comment)多行注释不能嵌套2.3变量声明(variabledeclare)2.3.1声明语法variable_nametype[CONSTANT][NOTNULL][:=value(初始值)]例:DECLAREv_TempVarNUMBERNOTNULL:=0;(此处不加初始值是不正确的)DECLAREc_MinimumStudentIDCONSTANTNUMBER(5):=10000;如果需要可以使用DEFAULT代替:=。c_MinimumStudentIDCONSTANTNUMBER(5)DEFAULT10000.在声明部分,每一行只能有一个变量声明。2.4PL/SQL类型标量(scalar)、复合(composite)、引用(reference)和LOB类型。2.4.1标量类型(scalartype)分为7个类:数字(numeric)、字符(character)、原生(raw)、日期(date)、行标识(rowid)、布尔(boolean)、可信任的(trusted)2.4.2使用%TYPE(一种良好的编程风格)例:DECLAREv_FirstNamestudents.first_name%TYPE;DECLAREv_RoomIDclasses.room_id%TYPE;--NUMBER(5);v_RoomID2v_RoomID%TYPE;--NUMBER(5);v_TmpVarNUMBER(7,3)NOTNULL:=12.3;v_AnotherVarv_TmpVar%TYPE;--NUMBER(7,3)如果%TYPE应用于一个限制为NOTNULL的列或变量,那么它返回的类型没有这个限制。2.4.3用户定义子类型SUBTYPEnew_type(新类型)ISoriginal_type(原类型)例:(1)DECLARESUBTYPEt_LoopCounterISNUMBER;--定义新的子类型v_LoopCountert_LoopCounter;--声明一个子类型的变量(2)DECLARESUBTYPEt_NameTypeISstudents.first_name%TYPE;SUBTYPE定义不能在定义中直接进行限制(constrain),可以有两种办法来解决。(1)DECLAREv_DummyVarNUMBER(4);--dummyvariable(哑变量)SUBTYPEt_LoopCounterISv_DummyVar%TYPE;v_Countert_LoopCounter;(2)DECLARESUBTYPEt_NumericISNUMBER;v_CounterISt_Numeric(5);2.4.4类型转换(typeconvert)隐式的(implicit)、显式的(explicit)相关函数TO_CHAR()--将来要把语法补上TO_DATE()TO_NUMBER()2.5表达式和运算符(expressionandoperator)2.5.1赋值(assignment)左值(lvalue)“:=”右值(rvalue)2.5.2字符运算符:“||”,逻辑运算符:“AND”、“OR”判断:ISNULL、LIKE(“_”、“%”)、BETWEEN、IN2.6PL/SQL控制结构2.6.1IF_THEN_ELSIF_ELSE_ENDIF注意:1)此处的ElseIf没有e,即ElsIf)2)ENDIF之间有空格3)与Pascal语法不一样的是:Else前的语句要以“;”结束。4)任何数与NULL比较的结果都为NULL。2.6.2循环1)简单循环LOOPEXIT[WHENcondition];ENDLOOP;例:DECLAREv_CounterBINARY_INTEGER:=1;BEGINLOOPINSERTINTOtmp_tableVALUES(v_Counter,'');v_Counter:=v_Counter+1;EXITWHENv_Counter50;ENDLOOP;END;2)While循环WHILEconditionLOOP[EXIT[WHENconditioni]](如果需要)ENDLOOP;注意:1)LOOP不是Pascal语法的“do”,2)此处不需要Pascal的“begin”和“end”例:DECLAREv_CounterBINARY_INTEGER:=1;BEGINWHILEv_Counter=50LOOPINSERTINTOtmp_tableVALUES(v_Counter,'');v_Counter:=v_Counter+1;ENDLOOP;END;3)For循环FORloop_counterIN[REVERSE]low_bound..high_boundLOOPENDLOOP;注意:1)循环变量loop_counter被隐式声明为BINARY_INTEGER类型,在循环前面没必要声明,2)如果声明,将隐蔽外部的声明(即循环变量相当于一个内部变量)。3)此处不需要Pascal的“begin”和“end”4)LOOP不是Pascal语法的“do”例:DECLAREv_CountNUMBER:=7;BEGININSERTINTOtmp_tableVALUES(v_Count,'');--此处v_Count为7FORv_CountIN20..30LOOPINSERTINTOtmp_tableVALUES(v_Count,'');--此处v_Count为20..30ENDLOOP;INSERTINTOtmp_tableVALUES(v_Count,'');--此处v_Count为7END;4)尽量不要使用GOTO语句5)pargma是一些编译器的指令。类似于C语言中的#pargma或#define或Delphi的{$}2.7PL/SQL风格指南2.7.1注释风格1)在每个块和过程的开始放置注释,解释要做什么。特别对于过程,列出哪个变量或参数的意义。另外列出被访问的数据库也是个好主意。2)在块的每个主要部分前添加注释2.7.2变量名风格要有描述性。例:v_VariableName程序变量e_ExceptionName用户定义的异常(错误)类型t_TypeName用户定义的类型p_ParameterName函数或过程的参数c_ConstantValue常量2.7.3大写风格1)保留字大写--BEGINENDDECLAREELSIF2)内置函数大写--SUBSTRCOUNTTO_CHAR3)预定义类型大写--NUMBER(7,3)BOOLEANDATE4)SQL关键字大写--SELECTINSERTUPDATEDELETEWHERE5)数据库对象小写--log_tableclassesstudents6)变量名使用大小写混合,名字的每个单词都大写--v_HireDatee_tooManyStudentst_StudentRecordType2.7.4缩进风格每个块向内缩2个空格。3第三章记录和表3.1PL/SQL记录记录类似于C中的结果,提供了处理分立的但又是作为一个整体单元的相关变量的一种机制。语法:TYPErecord_typeISRECORD(fieldtype1[NOTNULL][:=expr1],fieldtype2[NOTNULL][:=expr2],…);例:DECLARETYPEt_SampleRecordISRECORD(CountNUMBER(4),NameVARCHAR2(10):='Scott',EffectiveDateDATE,DescriptionVARCHAR2(45)NOTNULL:='Unknown');v_Sample1t_SampleRecord;v_Sample2t_SampleRecord;BEGINv_Sample1.Count:=9;--使用方法:用“.”(dotnotation)END;3.1.1记录赋值1)相同记录类型的变量可以互相赋值,如上面的2个记录变量可以这样v_Sample1:=v_Sample2;这样的赋值将使用“复制语义”(copysemantics[语义学])2)不同记录类型必须使用字段赋值方式,即使字段名和类型一样:如DECLARETYPEt_Rec1ISRECORD(Field1NUMBER);TYPEt_Rec2ISRECORD(Field1NUMBER);v_R1t_Rec1;v_R2t_Rec2;BEGIN/*这样是错误的,因为这两个变量不是一种记录类型*/v_Rec1:=v_Rec2;/*这样是正确的*/v_Rec1.Field1:=v_Rec2.Field1;v_Rec1.Field2:=v_Rec2.Field2;END;3)也可以使用SELECT语句对记录赋值,但查询选择结果列表中的字段吆喝记录中的字段顺序相匹配。例:DECLARE/