《游标和异常处理 oracle.docx》由会员分享,可在线阅读,更多相关《游标和异常处理 oracle.docx(21页珍藏版)》请在三一办公上搜索。
1、游标和异常处理游标的概念游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率。游标有两种类型:显式游标和隐式游标。在前述程序中用到的SELECT.INTO.查询语句,一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标。但是如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。显式游标对应一个返回结果为多行多
2、列的SELECT语句。游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。隐式游标如前所述,DML操作和单行SELECT语句会使用隐式游标,它们是:* 插入操作:INSERT。* 更新操作:UPDATE。* 删除操作:DELETE。* 单行查询操作:SELECT . INTO .。当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来
3、访问属性。游标的属性有四种,如下表所示。范例:使用隐式游标的属性,判断对雇员工资的修改是否成功。SET SERVEROUTPUT ON BEGIN UPDATE emp SET sal=sal+100 WHERE empno=1234; IF SQL%FOUND THEN DBMS_OUTPUT.PUT_LINE(成功修改雇员工资!); COMMIT; ELSEDBMS_OUTPUT.PUT_LINE(修改雇员工资失败!); END IF; END;说明:本例中,通过SQL%FOUND属性判断修改是否成功,并给出相应信息。显式游标游标的定义和操作游标的使用分成以下4个步骤。1声明游标在DECL
4、EAR部分按以下格式声明游标:CURSOR 游标名(参数1 数据类型,参数2 数据类型.) IS SELECT语句;参数是可选部分,所定义的参数可以出现在SELECT语句的WHERE子句中。如果定义了参数,则必须在打开游标时传递相应的实际参数。SELECT语句是对表或视图的查询语句,甚至也可以是联合查询。可以带WHERE条件、ORDER BY或GROUP BY等子句,但不能使用INTO子句。在SELECT语句中可以使用在定义游标之前定义的变量。2打开游标在可执行部分,按以下格式打开游标:OPEN 游标名(实际参数1,实际参数2.);打开游标时,SELECT语句的查询结果就被传送到了游标工作区。
5、3提取数据在可执行部分,按以下格式将游标工作区中的数据取到变量中。提取操作必须在打开游标之后进行。FETCH 游标名 INTO 变量名1,变量名2.;或FETCH 游标名 INTO 记录变量;游标打开后有一个指针指向数据区,FETCH语句一次返回指针所指的一行数据,要返回多行需重复执行,可以使用循环语句来实现。控制循环可以通过判断游标的属性来进行。下面对这两种格式进行说明:第一种格式中的变量名是用来从游标中接收数据的变量,需要事先定义。变量的个数和类型应与SELECT语句中的字段变量的个数和类型一致。第二种格式一次将一行数据取到记录变量中,需要使用%ROWTYPE事先定义记录变量,这种形式使用
6、起来比较方便,不必分别定义和使用多个变量。定义记录变量的方法如下:变量名 表名|游标名%ROWTYPE;其中的表必须存在,游标名也必须先定义。4关闭游标CLOSE 游标名;显式游标打开后,必须显式地关闭。游标一旦关闭,游标占用的资源就被释放,游标变成无效,必须重新打开才能使用。范例:以下是使用显式游标的一个简单练习。用游标提取emp表中7788雇员的名称和职务。(yb1.sql)SET SERVEROUTPUT ONDECLARE v_ename VARCHAR2(10); v_job VARCHAR2(10); CURSOR emp_cursor IS SELECT ename,job FR
7、OM emp WHERE empno=7788;BEGIN OPEN emp_cursor; FETCH emp_cursor INTO v_ename,v_job; DBMS_OUTPUT.PUT_LINE(v_ename|,|v_job); CLOSE emp_cursor;END;说明:该程序通过定义游标emp_cursor,提取并显示雇员7788的名称和职务。作为对以上例子的改进,在以下训练中采用了记录变量。范例:用游标提取emp表中7788雇员的姓名、职务和工资。(yb2.sql)SET SERVEROUTPUT ONDECLARE CURSOR emp_cursor IS SELE
8、CT ename,job,sal FROM emp WHERE empno=7788; emp_record emp_cursor%ROWTYPE;BEGINOPEN emp_cursor; FETCH emp_cursor INTO emp_record;DBMS_OUTPUT.PUT_LINE(emp_record.ename|,| emp_record.job|,| to_char(emp_record.sal); CLOSE emp_cursor;END;说明:实例中使用记录变量来接收数据,记录变量由游标变量定义,需要出现在游标定义之后。注意:可通过以下形式获得记录变量的内容:记录变量
9、名.字段名。范例: 显示工资最高的前3名雇员的名称和工资。(yb3.sql)SET SERVEROUTPUT ONDECLARE v_ename VARCHAR2(10); v_sal NUMBER(5); CURSOR emp_cursor IS SELECT ename,sal FROM emp ORDER BY sal DESC;BEGIN OPEN emp_cursor; FOR I IN 1.3 LOOP FETCH emp_cursor INTO v_ename,v_sal;DBMS_OUTPUT.PUT_LINE(v_ename|,|v_sal); END LOOP; CLOSE
10、 emp_cursor;END;说明:该程序在游标定义中使用了ORDER BY子句进行排序,并使用循环语句来提取多行数据。游标循环范例:使用特殊的FOR循环形式显示全部雇员的编号和名称。(yb4.sql)SET SERVEROUTPUT ONDECLARE CURSOR emp_cursor IS SELECT empno, ename FROM emp;BEGINFOR emp_record IN emp_cursor LOOP DBMS_OUTPUT.PUT_LINE(Emp_record.empno| Emp_record.ename);END LOOP;END;说明:可以看到该循环形式
11、非常简单,隐含了记录变量的定义、游标的打开、提取和关闭过程。Emp_record为隐含定义的记录变量,循环的执行次数与游标取得的数据的行数相一致。范例:另一种形式的游标循环。(yb5.sql)SET SERVEROUTPUT ON BEGIN FOR re IN (SELECT ename FROM EMP) LOOP DBMS_OUTPUT.PUT_LINE(re.ename); END LOOP;END;说明:该种形式更为简单,省略了游标的定义,游标的SELECT查询语句在循环中直接出现。显式游标属性虽然可以使用前面的形式获得游标数据,但是在游标定义以后使用它的一些属性来进行结构控制是一种
12、更为灵活的方法。显式游标的属性如下表所示。 可按照以下形式取得游标的属性:游标名%属性要判断游标emp_cursor是否处于打开状态,可以使用属性emp_cursor%ISOPEN。如果游标已经打开,则返回值为“真”,否则为“假”。具体可参照以下的训练。范例: 使用游标的属性练习。(yb6.sql)SET SERVEROUTPUT ONDECLARE v_ename VARCHAR2(10); CURSOR emp_cursor IS SELECT ename FROM emp;BEGIN OPEN emp_cursor; IF emp_cursor%ISOPEN THENLOOP FETCH
13、 emp_cursor INTO v_ename; EXIT WHEN emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(to_char(emp_cursor%ROWCOUNT)|-|v_ename); END LOOP; ELSE DBMS_OUTPUT.PUT_LINE(用户信息:游标没有打开!); END IF; CLOSE emp_cursor;END;说明:本例使用emp_cursor%ISOPEN判断游标是否打开;使用emp_cursor%ROWCOUNT获得到目前为止FETCH语句返回的数据行数并输出;使用循环来获取数据,在循环体中使用FETCH
14、语句;使用emp_cursor%NOTFOUND判断FETCH语句是否成功执行,当FETCH语句失败时说明数据已经取完,退出循环。练习:去掉OPEN emp_cursor;语句,重新执行以上程序。游标参数的传递(了解)范例:带参数的游标。(yb7.sql)SET SERVEROUTPUT ONDECLARE v_empno NUMBER(5); v_ename VARCHAR2(10); CURSOR emp_cursor(p_deptno NUMBER, p_job VARCHAR2) IS SELECTempno, ename FROM emp WHEREdeptno = p_deptno
15、 AND job = p_job;BEGIN OPEN emp_cursor(10, CLERK); LOOP FETCH emp_cursor INTO v_empno,v_ename; EXIT WHEN emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_empno|,|v_ename); END LOOP; END;说明:游标emp_cursor定义了两个参数:p_deptno代表部门编号,p_job代表职务。语句OPEN emp_cursor(10, CLERK)传递了两个参数值给游标,即部门为10、职务为CLERK,所以游标查询的内容是部门10的
16、职务为CLERK的雇员。循环部分用于显示查询的内容。练习:修改Open语句的参数:部门号为20、职务为ANALYST,并重新执行。也可以通过变量向游标传递参数,但变量需要先于游标定义,并在游标打开之前赋值。对以上例子重新改动如下:范例: 通过变量传递参数给游标。(yb8.sql)SET SERVEROUTPUT ONDECLARE v_empno NUMBER(5); v_ename VARCHAR2(10); v_deptno NUMBER(5);v_job VARCHAR2(10); CURSOR emp_cursor IS SELECT empno, ename FROM emp WHE
17、REdeptno = v_deptno AND job = v_job;BEGIN v_deptno:=10; v_job:=CLERK; OPEN emp_cursor; LOOP FETCH emp_cursor INTO v_empno,v_ename; EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_empno|,|v_ename); END LOOP;END;说明:该程序与前一程序实现相同的功能。利用游标删除和修改数据的时候要注意:UPDATE 表名 SET WHERE CURRENT OF 游标名;DELETE 表名 WHE
18、RE CURRENT OF 游标名;范例:定义游标emp_cur。通过使用游标,根据职务调整雇员的工资(yb9.sql)SET SERVEROUTPUT ONDECLARE v_job emp.job%TYPE; CURSOR emp_cur IS SELECT job FROM emp FOR UPDATE;BEGIN OPEN emp_cur; LOOP FETCH emp_cur INTO v_job; EXIT WHEN emp_cur%NOTFOUND; CASE WHEN v_job=CLERK THEN update emp set sal=sal+50 where curren
19、t of emp_cur; WHEN v_job=SALESMAN OR v_job=ANALYST THEN update emp set sal=sal+40 where current of emp_cur; ELSE update emp set sal=sal+10 where current of emp_cur;END CASE; END LOOP;COMMIT;END;/范例:用游标For循环,实现打印某一职务(输入一职务)的雇员的雇员编号和雇员姓名。(yb10.sql)可参考yb4.sqlDECLAREv_job emp.job%TYPE; CURSOR emp_cursor
20、 IS SELECT empno, ename FROM emp WHERE job=v_job;BEGINv_job:=&v_job;FOR emp_record IN emp_cursor LOOP DBMS_OUTPUT.PUT_LINE(Emp_record.empno| Emp_record.ename);END LOOP;END;异常处理错误处理错误处理部分位于程序的可执行部分之后,是由WHEN语句引导的多个分支构成的。错误处理的语法如下:EXCEPTIONWHEN 错误1OR 错误2 THEN语句序列1;WHEN 错误3OR 错误4 THEN语句序列2;WHEN OTHERS语句
21、序列n;END; 其中:错误是在标准包中由系统预定义的标准错误,或是由用户在程序的说明部分自定义的错误,参见下一节系统预定义的错误类型。语句序列就是不同分支的错误处理部分。凡是出现在WHEN后面的错误都是可以捕捉到的错误,其他未被捕捉到的错误,将在WHEN OTHERS部分进行统一处理,OTHERS必须是EXCEPTION部分的最后一个错误处理分支。如要在该分支中进一步判断错误种类,可以通过使用预定义函数SQLCODE( )和SQLERRM( )来获得系统错误号和错误信息。如果在程序的子块中发生了错误,但子块没有错误处理部分,则错误会传递到主程序中。下面是由于查询编号错误而引起系统预定义异常的
22、例子。范例:查询编号为1234的雇员名字。SET SERVEROUTPUT ONDECLAREv_name VARCHAR2(10);BEGIN SELECTename INTOv_name FROMemp WHEREempno = 1234;DBMS_OUTPUT.PUT_LINE(该雇员名字为:| v_name);EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE(编号错误,没有找到相应雇员!); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(发生其他错误!);END;说明:在以上查询中,因为编号为12
23、34的雇员不存在,所以将发生类型为“NO_DATA_FOUND”的异常。“NO_DATA_FOUND”是系统预定义的错误类型,EXCEPTION部分下的WHEN语句将捕捉到该异常,并执行相应代码部分。在本例中,输出用户自定义的错误信息“编号错误,没有找到相应雇员!”。如果发生其他类型的错误,将执行OTHERS条件下的代码部分,显示“发生其他错误!”范例:由程序代码显示系统错误。SET SERVEROUTPUT ONDECLAREv_temp NUMBER(5):=1;BEGINv_temp:=v_temp/0;EXCEPTION WHEN OTHERS THENDBMS_OUTPUT.PUT_
24、LINE(发生系统错误!); DBMS_OUTPUT.PUT_LINE(错误代码:| SQLCODE( ); DBMS_OUTPUT.PUT_LINE(错误信息: |SQLERRM( );END;说明:程序运行中发生除零错误,由WHEN OTHERS捕捉到,执行用户自己的输出语句显示错误信息,然后正常结束。在错误处理部分使用了预定义函数SQLCODE( )和SQLERRM( )来进一步获得错误的代码和种类信息。预定义错误(了解)Oracle的系统错误很多,但只有一部分常见错误在标准包中予以定义。定义的错误可以在EXCEPTION部分通过标准的错误名来进行判断,并进行异常处理。常见的系统预定义异
25、常如下表所示。比如,如果程序向表的主键列插入重复值,则将发生DUP_VAL_ON_INDEX错误。如果一个系统错误没有在标准包中定义,则需要在说明部分定义,语法如下:错误名 EXCEPTION;定义后使用PRAGMA EXCEPTION_INIT来将一个定义的错误同一个特别的Oracle错误代码相关联,就可以同系统预定义的错误一样使用了。语法如下:PRAGMA EXCEPTION_INIT(错误名,- 错误代码);范例:定义新的系统错误类型。SET SERVEROUTPUT ONDECLAREV_ENAME VARCHAR2(10);NULL_INSERT_ERROR EXCEPTION;PR
26、AGMA EXCEPTION_INIT(NULL_INSERT_ERROR,-1400);BEGININSERT INTO EMP(EMPNO) VALUES(NULL);EXCEPTIONWHEN NULL_INSERT_ERROR THEN DBMS_OUTPUT.PUT_LINE(无法插入NULL值!); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(发生其他系统错误!);END;执行结果为:无法插入NULL值!PL/SQL 过程已成功完成。说明:NULL_INSERT_ERROR是自定义异常,同系统错误1400相关联。自定义异常程序设计者可以利用引发异常的
27、机制来进行程序设计,自己定义异常类型。可以在声明部分定义新的异常类型,定义的语法是:错误名 EXCEPTION;用户定义的错误不能由系统来触发,必须由程序显式地触发,触发的语法是:RAISE 错误名;RAISE也可以用来引发模拟系统错误,比如,RAISE ZERO_DIVIDE将引发模拟的除零错误。使用RAISE_APPLICATION_ERROR函数也可以引发异常。该函数要传递两个参数,第一个是用户自定义的错误编号,第二个参数是用户自定义的错误信息。使用该函数引发的异常的编号应该在20 000和20 999之间选择。自定义异常处理错误的方式同前。范例:插入新雇员,限定插入雇员的编号在7000
28、8000之间。SET SERVEROUTPUT ONDECLAREnew_no NUMBER(10);new_excp1 EXCEPTION;new_excp2 EXCEPTION;BEGINnew_no:=6789;INSERT INTOemp(empno,ename) VALUES(new_no, 小郑); IF new_no8000 THEN RAISE new_excp2; END IF; COMMIT;EXCEPTIONWHEN new_excp1 THENROLLBACK;DBMS_OUTPUT.PUT_LINE(雇员编号小于7000的下限!); WHEN new_excp2 TH
29、EN ROLLBACK; DBMS_OUTPUT.PUT_LINE(雇员编号超过8000的上限!);END;执行结果为:雇员编号小于7000的下限!PL/SQL 过程已成功完成。说明:在此例中,自定义了两个异常:new_excp1和new_excp2,分别代表编号小于7000和编号大于8000的错误。在程序中通过判断编号大小,产生对应的异常,并在异常处理部分回退插入操作,然后显示相应的错误信息。范例:使用RAISE_APPLICATION_ERROR函数引发系统异常。SET SERVEROUTPUT ONDECLARENew_no NUMBER(10);BEGIN New_no:=6789;
30、INSERT INTOemp(empno,ename) VALUES(new_no, JAMES);IF new_no8000 THEN ROLLBACK; RAISE_APPLICATION_ERROR (-20002, 编号大于8000的下限!); END IF;END;执行结果为:DECLARE*ERROR 位于第 1 行:ORA-20001: 编号小于7000的下限!ORA-06512: 在line 9说明:在本训练中,使用RAISE_APPLICATION_ERROR引发自定义异常,并以系统错误的方式进行显示。错误编号为20001和20002。注意:同上一个训练比较,此种方法不需要事
31、先定义异常,可直接引发。 可以参考下面的程序片断将出错信息记录到表中,其中,errors为记录错误信息的表,SQLCODE为发生异常的错误编号,SQLERRM为发生异常的错误信息。DECLARE v_error_code NUMBER; v_error_message VARCHAR2(255);BEGIN.EXCEPTION.WHEN OTHERS THEN v_error_code := SQLCODE ; v_error_message := SQLERRM ; INSERT INTO errors VALUES(v_error_code, v_error_message);END;练习
32、:修改雇员的工资,通过引发异常控制修改范围在6006000之间。存储过程、函数和包认识存储过程和函数存储过程和函数也是一种PL/SQL块,是存入数据库的PL/SQL块。但存储过程和函数不同于已经介绍过的PL/SQL程序,我们通常把PL/SQL程序称为无名块,而存储过程和函数是以命名的方式存储于数据库中的。和PL/SQL程序相比,存储过程有很多优点,具体归纳如下:l 存储过程和函数以命名的数据库对象形式存储于数据库当中。存储在数据库中的优点是很明显的,因为代码不保存在本地,用户可以在任何客户机上登录到数据库,并调用或修改代码。l 存储过程和函数可由数据库提供安全保证,要想使用存储过程和函数,需要
33、有存储过程和函数的所有者的授权,只有被授权的用户或创建者本身才能执行存储过程或调用函数。l 存储过程和函数的信息是写入数据字典的,所以存储过程可以看作是一个公用模块,用户编写的PL/SQL程序或其他存储过程都可以调用它(但存储过程和函数不能调用PL/SQL程序)。一个重复使用的功能,可以设计成为存储过程,比如:显示一张工资统计表,可以设计成为存储过程;一个经常调用的计算,可以设计成为存储函数;根据雇员编号返回雇员的姓名,可以设计成存储函数。l 像其他高级语言的过程和函数一样,可以传递参数给存储过程或函数,参数的传递也有多种方式。存储过程可以有返回值,也可以没有返回值,存储过程的返回值必须通过参
34、数带回;函数有一定的数据类型,像其他的标准函数一样,我们可以通过对函数名的调用返回函数值。l 存储过程和函数需要进行编译,以排除语法错误,只有编译通过才能调用。创建和删除存储过程创建存储过程,需要有CREATE PROCEDURE或CREATE ANY PROCEDURE的系统权限。该权限可由系统管理员授予。创建一个存储过程的基本语句如下:CREATE OR REPLACE PROCEDURE 存储过程名(参数IN|OUT|IN OUT 数据类型.)AS|IS说明部分BEGIN可执行部分EXCEPTION 错误处理部分END 过程名;其中:可选关键字OR REPLACE 表示如果存储过程已经存
35、在,则用新的存储过程覆盖,通常用于存储过程的重建。参数部分用于定义多个参数(如果没有参数,就可以省略)。参数有三种形式:IN、OUT和IN OUT。如果没有指明参数的形式,则默认为IN。关键字AS也可以写成IS,后跟过程的说明部分,可以在此定义过程的局部变量。编写存储过程可以使用任何文本编辑器或直接在SQL*Plus环境下进行,编写好的存储过程必须要在SQL*Plus环境下进行编译,生成编译代码,原代码和编译代码在编译过程中都会被存入数据库。编译成功的存储过程就可以在Oracle环境下进行调用了。一个存储过程在不需要时可以删除。删除存储过程的人是过程的创建者或者拥有DROP ANY PROCE
36、DURE系统权限的人。删除存储过程的语法如下:DROP PROCEDURE 存储过程名;如果要重新编译一个存储过程,则只能是过程的创建者或者拥有ALTER ANY PROCEDURE系统权限的人。语法如下:ALTER PROCEDURE 存储过程名 COMPILE;执行(或调用)存储过程的人是过程的创建者或是拥有EXECUTE ANY PROCEDURE系统权限的人或是被拥有者授予EXECUTE权限的人。执行的方法如下:方法1:EXECUTE 模式名.存储过程名(参数.);方法2:BEGIN模式名.存储过程名(参数.);END;传递的参数必须与定义的参数类型、个数和顺序一致(如果参数定义了默认
37、值,则调用时可以省略参数)。参数可以是变量、常量或表达式,用法参见下一节。如果是调用本账户下的存储过程,则模式名可以省略。要调用其他账户编写的存储过程,则模式名必须要添加。以下是一个生成和调用简单存储过程的训练。注意要事先授予创建存储过程的权限。范例:创建一个显示雇员总人数的存储过程。步骤1:登录SCOTT账户。步骤2:在SQL*Plus输入区中,输入以下存储过程:CREATE OR REPLACE PROCEDURE EMP_COUNTASV_TOTAL NUMBER(10);BEGIN SELECT COUNT(*) INTO V_TOTAL FROM EMP; DBMS_OUTPUT.P
38、UT_LINE(雇员总人数为:|V_TOTAL);END;步骤3:/执行是进行编译。如果存在错误,就会显示:警告: 创建的过程带有编译错误。如果存在错误,对脚本进行修改,直到没有错误产生。如果要想查看编译的错误:SHOW ERRORS PROCEDURE emp_count;如果编译结果正确,将显示:过程已创建。步骤4:调用存储过程,在输入区中输入以下语句并执行:EXECUTE EMP_COUNT;显示结果为:雇员总人数为:14PL/SQL 过程已成功完成。说明:在该训练中,V_TOTAL变量是存储过程定义的局部变量,用于接收查询到的雇员总人数。注意:在SQL*Plus中输入存储过程,按“执行
39、”按钮是进行编译,不是执行存储过程。如果在存储过程中引用了其他用户的对象,比如表,则必须有其他用户授予的对象访问权限。一个存储过程一旦编译成功,就可以由其他用户或程序来引用。但存储过程或函数的所有者必须授予其他用户执行该过程的权限。存储过程没有参数,在调用时,直接写过程名即可。注意:用EXECUTE调用存储过程只有两种情况:一种是存储过程不带参数一种是存储过程不带输出参数,带输入参数不是变量带入是直接带入范例:在PL/SQL程序中调用存储过程。步骤1:登录SCOTT账户。步骤2:授权STUDENT账户使用该存储过程,即在SQL*Plus输入区中,输入以下的命令:GRANT EXECUTE ON
40、 EMP_COUNT TO STUDENT授权成功。步骤3:登录STUDENT账户,在SQL*Plus输入区中输入以下程序:SET SERVEROUTPUT ONBEGINSCOTT.EMP_COUNT;END;步骤4:执行以上程序,结果为:雇员总人数为:14PL/SQL 过程已成功完成。 说明:在本例中,存储过程是由SCOTT账户创建的,STUDEN账户获得SCOTT账户的授权后,才能调用该存储过程。 注意:在程序中调用存储过程,使用了第二种语法。范例:编写显示雇员信息的存储过程EMP_LIST,并引用EMP_COUNT存储过程。步骤1:在SQL*Plus输入区中输入并编译以下存储过程:CR
41、EATE OR REPLACE PROCEDURE EMP_LISTAS CURSOR emp_cursor IS SELECT empno,ename FROM emp;BEGINFOR Emp_record IN emp_cursor LOOP DBMS_OUTPUT.PUT_LINE(Emp_record.empno|Emp_record.ename); END LOOP; EMP_COUNT;END;执行结果:过程已创建。步骤2:调用存储过程,在输入区中输入以下语句并执行:EXECUTE EMP_LIST说明:以上的EMP_LIST存储过程中定义并使用了游标,用来循环显示所有雇员的信息
42、。然后调用已经成功编译的存储过程EMP_COUNT,用来附加显示雇员总人数。通过EXECUTE命令来执行EMP_LIST存储过程。练习:编写显示部门信息的存储过程DEPT_LIST,要求统计出部门个数。参数传递参数的作用是向存储过程传递数据,或从存储过程获得返回结果。正确的使用参数可以大大增加存储过程的灵活性和通用性。参数的类型有三种,如表8-1所示。参数的定义形式和作用如下:参数名 IN 数据类型 DEFAULT 值;定义一个输入参数变量,用于传递参数给存储过程。在调用存储过程时,主程序的实际参数可以是常量、有值变量或表达式等。DEFAULT 关键字为可选项,用来设定参数的默认值。如果在调用
43、存储过程时不指明参数,则参数变量取默认值。在存储过程中,输入变量接收主程序传递的值,但不能对其进行赋值。参数名 OUT 数据类型;定义一个输出参数变量,用于从存储过程获取数据,即变量从存储过程中返回值给主程序。在调用存储过程时,主程序的实际参数只能是一个变量,而不能是常量或表达式。在存储过程中,参数变量只能被赋值而不能将其用于赋值,在存储过程中必须给输出变量至少赋值一次。参数名 IN OUT 数据类型 DEFAULT 值;定义一个输入、输出参数变量,兼有以上两者的功能。在调用存储过程时,主程序的实际参数只能是一个变量,而不能是常量或表达式。DEFAULT 关键字为可选项,用来设定参数的默认值。在存储过程中,变量