子程序包括过程和函数。这里的所谓函数是指用户自定义函数。
从pl/sql程序设计的角度,也可以把子程序认为是pl/sql命名块,它存放在数据字典中,
可以在应用程序中进行多次调用。
子程序存放在数据库服务器中,以编译方式运行,执行速度快。子程序一般是完成特定
功能的pl/sql程序块,具有一定的通用性,可以被不同应用程序多次调用,这样就简化了
应用程序的开发与维护,并能提高应用程序的性能。让用户程序通过调用子程序访问数据库,
而不是让用户程序直接访问数据库,这样做可以确保数据库的安全。
一、过程
如果在用户应用中经常要执行某些操作,那么就可以将这些操作构造为一个过程。默认情况下,
用户定义的过程为该用户所拥有,数据库管理员可以把过程的使用权限授予其他用户。
1.定义过程
语法格式:
1 create [or replace] procedure procedure_name 2 [(argument_name [in | out | in out] argument_type [, ...])] 3 is | as 4 begin 5 procedure_body 6 end [procedure_name];
--argument_name指定参数的名字;argument_type指定参数的数据类型
--[in | out | in out]指定参数的模式,其中in表示参数是输入给过程的,out表示参数在过程中将被赋值
--in out表示该类型的参数既可以向过程体传递值,也可以在过程体中赋值,可以传给过程体的外部。
--关键字is和as可任选其一
1 create or replace procedure display_teacher( 2 v_no teacher.department_id%type 3 ) 4 as 5 v_wage teachers.wage%type; 6 v_maxwage teachers.wage%type; 7 v_minwage teachers.wage%type; 8 begin 9 select avg(wage) into v_wage 10 from teachers where department_id = v_no; 11 select max(wage) into v_wage 12 from teachers where department_id = v_no; 13 select min(wage) into v_wage 14 from teachers where department_id = v_no; 15 dbms_output.put_line('该系平均工资为:' || v_wage); 16 dbms_output.put_line('该系最高工资为:' || v_maxwage); 17 dbms_output.put_line('该系最低工资为:' || v_minwage); 18 exception 19 when no_data_found then 20 dbms_output.put_line('该系不存在。'); 21 end display_teacher;
2.调用过程
语法格式:
call | execute procedure_name(argument_list);
--关键字call和execute任选其一;procedure_name指定调用过程的名称;
--argument_list指定调用过程所需要传递的参数列表。
set serveroutput on
--使用CALL语句
call display_teacher(101);
--使用execute语句
execute display_teacher(101);
3.过程的管理
过程的管理包括查看已建立过程的有关信息、查看过程中的错误、修改过程中的错误及删除过程等。
(1)查看已建立过程的有关信息
1 --通过数据字典中的user_objects视图,可以查看过程(对象)名object_name、过程建立时间created、
过程状态图status等信息。 2 select object_name, created, status 3 from user_objects 4 where object_name = 'display_teacher'; 5 --通过数据字典中的user_source视图,可以查看过程的源程序。 6 select text from user_source 7 where name = 'display_teacher';
(3)查看与修改过程中的错误
在建立过程时,如果oracle系统报告错误,可以通过sql中的命令show errors查看错误信息,
通过sql中的命令edit修改错误。
1 create or replace procedure display_teacher( 2 v_no teacher.department_id%type 3 ) 4 as 5 v_wage teachers.wage%type; 6 v_maxwage teachers.wage%type; 7 v_minwage teachers.wage%type; 8 begin 9 select avg(wage) into v_wage 10 from teachers wheree department_id = v_no; 11 select max(wage) into v_wage 12 from teachers where department_id = v_no; 13 select min(wage) into v_wage 14 from teachers where department_id = v_no; 15 dbms_output.put_line('该系平均工资为:' || v_wage); 16 dbms_output.put_line('该系最高工资为:' || v_maxwage); 17 dbms_output.put_line('该系最低工资为:' || v_minwage); 18 exception 19 when no_data_found then 20 dbms_output.put_line('该系不存在。'); 21 end display_teacher;
--警告:创建的过程带有编译错误。
show errors
******
edit
(3)删除过程
语法格式:
drop procedure procedure_name;
drop procedure display_teacher;
4.参数及其传递
建立过程时,传递的参数为可选项。如果省略参数选项,则过程为无参数过程——定义时
不指定参数,调用时也不需要参数;如果指定参数选项,则过程为有参数过程——定义时需
要指定参数名字、模式、数据类型,调用时需要给出对应参数。定义过程时指定的参数称为
形参,调用过程时给出的参数称为实参。
(1)无参数过程
1 create or replace procedure display_systime 2 as 3 begin 4 dbms_output.out_line('系统时间为:' || sysdate); 5 end display_system; 6 set serveroutput on 7 call display_systime();
(2)有参数过程
带有参数的过程定义时需要指定参数名字、模式、数据类型,调用时需要给出对应参数。
--使用in参数
1 create or replace procedure app_student( 2 v_no in students.student_id%type, 3 v_monitor_id in students.monitor_id%type, 4 v_name in students.name%type, 5 v_sex in students.sex%type, 6 v_dob in students.dob%type, 7 v_specialty in students.specialty%type 8 ) 9 as 10 begin 11 insert into students values( 12 v_no, v_monitor_id, v_name, v_sex, v_dob, v_specialty 13 ); 14 exception 15 when dup_val_on_index then 16 dbms_output.put_line('插入学生信息时,学生号不能重复'); 17 end; 18 call app_student(101,102,'飞鸿','男','03-4月-1987','自动化'); 19 --使用in和out参数 20 create or replace procedure display_edited( 21 v_id in teachers.teacher_id%type, 22 v_name out teachers.name%type, 23 v_wage out teachers.wage%type 24 ) 25 as 26 v_title teachers.title%type; 27 begin 28 select title into v_title 29 from teachers where teacher_id = v_id; 30 case 31 when v_title = '教授' then 32 update teachers 33 set wage = 1.1 * wage where teacher_id = v_id; 34 when v_title = '高工' or v_title = '副教授' then 35 update teachers 36 set wage = 1.1 * wage where teacher_id = v_id; 37 else 38 update teachers 39 set wage = wage + 100 where teacher_id = v_id; 40 end case; 41 select name, wage into v_name, v_wage 42 from teacher where teacher_id = v_id; 43 end display_edited; 44 variable v_name varchar2(10) 45 variable v_wage number 46 call display_edited(10101, :v_name, :v_wage); 47 --使用In out参数 48 create or replace procedure app_disp( 49 v_id in out departments.department_id%type, 50 v_name in out departments.department_name%type, 51 v_address in out departments.address%type 52 ) 53 as 54 begin 55 insert into departments 56 values(v_id, v_name, v_address); 57 v_id := v_id - 1; 58 select department_id, department_name, address 59 into v_id, v_name, v_address 60 from departments 61 where department_id = v_id; 62 exception 63 when dup_val_on_index then 64 dbms_output.put_line('插入系部信息时,系部号不能重复'。); 65 when no_data_found then 66 dbms_output.put_line('查询系部信息时,该系不存在。'); 67 end; 68 variable v_id number 69 variable v_name varchar2(8) 70 variable v_address varchar2(40) 71 execute :v_id := 111 72 execute :v_name := '地理' 73 execute :v_address := 'X号教学楼'; 74 call app_disp(:v_id, :v_name, :v_address);
(3)参数传递方式
前面的例子,在调用带有参数的过程时,实参都是按照位置与形参进行对应传递的。
pl/sql同时也提供另外一种参数传递方式——按照参数名称传递。由于在传递多个参数时,
一些参数可以按照参数位置传递,另一些参数可以按照参数名称传递。因此,又有了混合传递参数的方式。
--参数传递使用名字传递方式
execute app_student(v_no => 10166, v_monitor_id => 10101,
v_name => '张三', v_sex => '男', v_dob => '21-7月-1989', v_specialty => '计算机');
--参数传递使用混合传递方式
execute app_student(10177, 10101,
v_name => '老四', v_sex => '男', v_dob => '22-5月-1989', v_specialty => '计算机');
过程和函数的区别:
过程:
作为 PL/SQL 语句执行;
在规范中不包含 RETURN 子句;
不返回任何值(只有输入/输出参数,结果集);
可以包含 RETURN 语句,但是与函数不同,它不能用于返回值。
函数:
作为表达式的一部分调用;
必须在规范中包含 RETURN 子句;
必须返回单个值;
必须包含至少一条 RETURN 语句。