PLSQL 之类型、变量和结构
1、类型在《.Net程序员学用Oracle系列(5):三大数据类型》一文中详细地讲述了 Oracle 的基本数据类型,文中还提到,除基本数据类型之外,Oracle 还在语法上支持一些非固有数值类型。 事实上,Oracle 在语法上支持的数据类型远不止于此,Oracle 还支持一些复杂而强大的数据类型。如属性类型 1.1、属性类型属性类型是一种可以直接引用数据库中列的数据类型来描述变量类型的类型。Oracle 提供了两种属性类型,分别是 %TYPE:该属性允许在声明中引用数据库中的列或先前声明的变量的数据类型,而不是硬编码类型名称。在声明常量、变量和参数时,都可以使用 示例: DECLARE v_staff_namet_staff.staff_name%TYPE;BEGIN SELECTt.staff_nameINTOv_staff_nameFROMdemo.t_stafftWHEREt.staff_id=5; DBMS_OUTPUT.PUT_LINE(v_staff_name);END; %ROWTYPE:该属性可以表示数据库中表或游标的行的记录类型。使用 DECLARE v_stafft_staff%ROWTYPE;BEGIN SELECTt.*INTOv_staffFROMdemo.t_stafftWHEREt.staff_id=5; DBMS_OUTPUT.PUT_LINE(v_staff.staff_name);END; 想要更多的了解属性类型可参考:《Database PL/SQL User's Guide and Reference: %TYPE Attribute》和《Database PL/SQL User's Guide and Reference: %ROWTYPE Attribute》。 1.2、记录类型记录类型是由单行多列标量构成的复合结构。可以看做是一种用户自定义的数据类型,提供了将一个或多个标量封装成一个对象进行操作的能力。在使用记录数据类型的变量时,需要在声明部分先定义记录的成员变量,然后在执行部分引用该记录变量本身或其中的成员。但不可以对记录做整体性的比较运算,如判断记录类型的变量是否为 NULL。 DECLARE TYPEstaff_typeISRECORD( staff_nameVARCHAR2(50),genderVARCHAR2(2) ); v_staffstaff_type;BEGIN SELECTt.staff_name,DECODE(t.gender,1,'男','女','两性')INTOv_staff.staff_name,v_staff.genderFROMdemo.t_stafftWHEREt.staff_id=5; DBMS_OUTPUT.PUT_LINE(v_staff.staff_name||'|'||v_staff.gender);END; 记录类型和 2、变量一般计算机编程语言中都有变量的概念,PL/SQL 也不例外,变量用于存储计算结果和表示可变状态,本节将着重介绍在 PL/SQL 中变量如何定义及赋值。另外,PL/SQL 中也有常量,只是极少有人使用,有兴趣的读者可以参考《Oracle Database PL/SQL Language Reference: Constant》。 2.1、变量类型在 PL/SQL 中定义变量的可选类型非常多,包括 Oracle 中常见的三大类基本数据类型,以及 Oracle 在语法上支持的诸多非固有数据类型。如整形(INT/INTEGER)、布尔类型(BOOLEAN)等 Oracle 本身并不支持,却在 PL/SQL 中可用的数据类型。 2.2、变量定义在 PL/SQL 中定义变量与 C# 中定义变量本质上并无区别,不同的是 PL/SQL 中的变量得集中定义,变量定义区域得用 语法: variable_namedatatype[[NOTNULL]{:=|DEFAULT}expression]; 如果使用了 NOT NULL 则必须给变量赋初始值。另外,在命名变量的时候还需要遵守以下命名规则:
2.3、变量赋值给 PL/SQL 变量赋值的写法与给 C# 字段赋值写法基本一样,既可以在定义变量时就赋给它一个初始值,也可以在使用之前给它赋值,如果不赋值也会有默认值。唯一的区别就是,C# 中类型不同默认值也不同,而 PL/SQL 中所有类型的默认值都一样,都是 NULL。 在 PL/SQL 中还有一点比较怪的就是,可能所有编程语言的赋值操作符都是 示例一(普通 PL/SQL 环境): DECLARE v1NUMBER; v2NUMBER(5,2); v3NUMBER:=50.20; v4NUMBER(4):=1998; v5VARCHAR2(4)DEFAULT'A'; v6DATENOTNULL:=fn_now;BEGIN v1:=100; v2:=99.99; v5:='A5'; v6:=SYSDATE;DBMS_OUTPUT.PUT_LINE(v1||'|'||v2||'|'||v3||'|'||v4||'|'||v5||'|'||v6);END; 示例二(SQL*Plus 环境): VARIABLEv1NUMBERBEGIN :v1:=12; DBMS_OUTPUT.PUT_LINE(:v1);END;/ 3、结构和普通编程语言一样,PL/SQL 中也有常见的三大控制结构以及顺序控制语句――GOTO。本节将重点讲述被广泛接受的三大控制结构,至于不受待见的 GOTO 语句,有兴趣的读者可以参考《Oracle Database PL/SQL User's Guide and Reference: Using the GOTO Statement》。 3.1、顺序结构顺序结构是面向过程编程中最基本、最简单、最常用的程序控制结构。顺序结构用于表示若干个依次执行的处理步骤,表现形式就是线性结构,一个方向走下去、不拐弯。使用时只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下、依次执行。 3.2、选择结构PL/SQL 中提供了两种选择结构,分别是 IF 结构变体一: IFconditionTHEN {...statementstoexecutewhenconditionisTRUE...}ENDIF; BEGIN IF1>0THEN DBMS_OUTPUT.PUT_LINE('executed');ENDIF;END; IF 结构变体二: IFconditionTHEN {...statementstoexecutewhenconditionisTRUE...}ELSE {...statementstoexecutewhenconditionisFALSE...}ENDIF; BEGIN IF1>2THEN DBMS_OUTPUT.PUT_LINE('Theresultistrue'); ELSE DBMS_OUTPUT.PUT_LINE('Theresultisfalse');ENDIF;END; IF 结构变体三: IFcondition1THEN {...statementstoexecutewhencondition1isTRUE...}ELSIFcondition2THEN {...statementstoexecutewhencondition2isTRUE...}[ELSE {...statementstoexecutewhenbothcondition1andcondition2areFALSE...}]ENDIF; BEGIN IF1>2THEN DBMS_OUTPUT.PUT_LINE('1>2branch'); ELSIF1<2THEN DBMS_OUTPUT.PUT_LINE('1<2branch');ELSE DBMS_OUTPUT.PUT_LINE('1=2branch');ENDIF;END; 注意:IF 结构变体三中有个巨坑,就是 IF 和 ELSE 之间的分支写法,不是 ELSE IF 也不是 ELSEIF 而是 ELSIF。尽管你写成 ELSE IF 编辑器也有智能提示,但当你执行的时候就会报 CASE 结构变体一 DECLARE v_gradeVARCHAR2(1);BEGIN v_grade:='B';CASEv_grade WHEN'A'THENDBMS_OUTPUT.PUT_LINE('甲'); WHEN'B'THENDBMS_OUTPUT.PUT_LINE('乙'); WHEN'C'THENDBMS_OUTPUT.PUT_LINE('丙');ELSEDBMS_OUTPUT.PUT_LINE('丁');ENDCASE;END; CASE 结构变体二 DECLARE v_scoreNUMBER(3); BEGIN v_score:=78;CASE WHENv_score>=80THENDBMS_OUTPUT.PUT_LINE('优'); WHENv_score>=70THENDBMS_OUTPUT.PUT_LINE('良'); WHENv_score>=60THENDBMS_OUTPUT.PUT_LINE('中'); ELSEDBMS_OUTPUT.PUT_LINE('差'); ENDCASE;END; 与多分支的 IF 语句相比,CASE 语句更可读、更高效,所以当程序分支较多时,应尽可能的使用 CASE 而不是 IF。CASE 语句的 ELSE 子句是可选的。但如果省略 ELSE 字句,PL/SQL 将为 CASE 语句添加以下隐式的 ELSE 子句: ELSERAISECASE_NOT_FOUND; 换句话说,如果你省略了 ELSE 子句,且 CASE 语句与 WHEN 子句不匹配,PL/SQL 就会引发预定义的异常 3.3、循环结构PL/SQL 中提供了三种循环结构,分别是 LOOP 循环 LOOP{...statements...} EXIT[WHENboolean_condition];ENDLOOP; 示例一: DECLARE v_counterBINARY_INTEGER:=0; BEGINLOOP v_counter:=v_counter+1; DBMS_OUTPUT.PUT_LINE(v_counter);--输出结果:1、2、3、4、5、6、7、8、9 IFv_counter>=9THEN EXIT;ENDIF; --上面的IF语句块还可以由“EXITWHENv_counter>=9;”代替ENDLOOP;END; 示例二(嵌套循环): DECLAREiBINARY_INTEGER:=0;jBINARY_INTEGER:=0; BEGIN LOOPi:=i+1;j:=0; LOOPj:=j+1; DBMS_OUTPUT.PUT_LINE('i*j=('||i||'*'||j||')='||i*j); EXITWHENj>=3; ENDLOOP; EXITWHENi>=4; ENDLOOP; END; 示例三(标记循环): DECLAREiBINARY_INTEGER:=0;jBINARY_INTEGER:=0; BEGIN <<outer_loop>> LOOPi:=i+1;j:=0; <<inner_loop>> LOOPj:=j+1; DBMS_OUTPUT.PUT_LINE('i*j=('||i||'*'||j||')='||i*j); EXITinner_loopWHENj>=3; EXITouter_loopWHENi>=4; ENDLOOPinner_loop; ENDLOOPouter_loop; END; WHILE LOOP 循环 WHILEcondition LOOP{...statements...}ENDLOOP; DECLARE v_scoreNUMBER(3):=0;BEGIN WHILEv_score<60LOOP v_score:=v_score+10; DBMS_OUTPUT.PUT_LINE(v_score);--输出结果:10、20、30、40、50、60 ENDLOOP; DBMS_OUTPUT.PUT_LINE('over');END; FOR LOOP 循环 FORloop_counterIN[REVERSE]lowest_number..highest_number LOOP{...statements...}ENDLOOP; 示例一(正向循环): BEGIN FORiIN3..7LOOP DBMS_OUTPUT.PUT_LINE(i);--输出结果:3、4、5、6、7 ENDLOOP;END; 示例二(反向循环): BEGIN FORiINREVERSE3..7LOOP DBMS_OUTPUT.PUT_LINE(i);--输出结果:7、6、5、4、3 ENDLOOP;END; 注意:FOR LOOP 循环中的计数器(变量)可以被读取,但不能被修改。另外,在 LOOP 循环的示例中用到的 EXIT 和循环标记,同样可用于 WHILE LOOP 循环和 FOR LOOP 循环中 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |