在本章中,我们将讨论pl/sql中的存储过程。 子程序是执行特定任务的程序单元/模块。 这些子程序组合起来形成更大的程序。这种做法被称为“模块化设计”。 子程序可以被称为调用程序的另一个子程序或程序调用。
可以在以下几个地方中创建一个子程序 -
在模式(schema)级别中,子程序是一个独立的子程序。它是使用create procedure
或create function
语句创建的。它存储在数据库中,可以使用drop procedure
或drop function
语句进行删除。
在包中创建的子程序是打包的子程序。它存储在数据库中,只有当使用drop package
语句删除程序包时,才能将其删除。我们将在“pl/sql程序包”一章中讨论程序包的应用。
pl/sql子程序被命名为可以使用一组参数调用的pl/sql块。 pl/sql提供两种子程序 -
本章将主要介绍pl/sql中的存储过程。在下一章介绍讨论pl/sql函数。
每个pl/sql子程序都有一个名称,也可能有一个参数列表。 像匿名pl/sql块一样,命名块也将具有以下三个部分 -
编号 | 部分 | 描述 |
---|---|---|
1 | 声明部分 | 这是一个可选的部分。但是,子程序的声明部分不以declare 关键字开头。 它包含类型,游标,常量,变量,异常和嵌套子程序的声明。这些项是本子程序,当子程序完成执行时,它们将不复存在。 |
2 | 可执行部分 | 这是一个强制性部分(必须有),并包含执行指定操作的语句。 |
3 | 异常处理 | 这是一个可选的部分。它包含处理运行时错误的代码。 |
可使用create or replace procedure
语句来创建一个存储过程。 create or replace procedure
语句的简化语法如下:
create [or replace] procedure procedure_name
[(parameter_name [in | out | in out] type [, ...])]
{is | as}
begin
< procedure_body >
end procedure_name;
其中,
in
表示将从外部传递的值,out
表示将用于返回过程外的值的参数。as
关键字而不是is
关键字来创建存储过程。例子
以下示例演示如何创建一个简单的存储过程,执行时它只显示字符串“hello world!”
在屏幕上。
set serveroutput on size 99999;
create or replace procedure greetings
as
begin
dbms_output.put_line('hello world!');
end;
/
-- 执行存储过程
exec greetings;
-- 或者
execute greetings;
当使用sql提示符执行上述代码时,它将产生以下结果 -
独立的存储程序可以通过两种方式调用 -
execute
关键字可以使用execute
关键字调用名为“greetings”
的存储过程如下 -
execute greetings;
上述调用将显示结果为 -
sql> execute greetings;
hello world!
pl/sql 过程已成功完成。
sql>
该过程也可以从另一个pl/sql块调用,例如 -
begin
greetings;
end;
/
执行上面示例代码,得到以下结果 -
sql> begin
2 greetings;
3 end;
4 /
hello world!
pl/sql 过程已成功完成。
sql>
使用drop procedure
语句删除独立存储过程。删除程序的语法是 -
drop procedure procedure-name;
可以使用以下语句删除greetings
存储过程程序 -
drop procedure greetings;
下表列出了pl/sql子程序中的参数模式 -
编号 | 参数模式 | 描述 |
---|---|---|
1 | in |
in 参数允许将值传递给子程序。它是一个只读参数。在子程序中,in 参数的作用如常数,它不能被赋值。可以将常量,文字,初始化的变量或表达式作为in 参数传递。也可以将其初始化为默认值; 然而,在这种情况下,从子程序调用中省略它。 它是参数传递的默认模式。参数通过引用传递。 |
2 | out |
out 参数返回一个值给调用程序。在子程序中,out 参数像变量一样。 可以更改其值并在分配该值后引用该值。实际参数必须是可变的,并且通过值传递。 |
3 | in out |
in out 参数将初始值传递给子程序,并将更新的值返回给调用者。 它可以分配一个值,该值可以被读取。对应于in out 形式参数的实际参数必须是变量,而不是常量或表达式。正式参数必须分配一个值。实际参数(实参)通过值传递。 |
in和out模式 - 示例1
假设以下存储过程需要求出两个值中的最小值。这里,存储过程两个输入的数字使用in
模式,并使用out
模式参数返回最小值。
set serveroutput on size 99999;
declare
a number;
b number;
c number;
procedure findmin(x in number, y in number, z out number) is
begin
if x < y then
z:= x;
else
z:= y;
end if;
end;
begin
a:= 12;
b:= 35;
findmin(a, b, c);
dbms_output.put_line('两个数:12, 35中的最小值是 : ' || c);
end;
/
当上述代码在sql提示符下执行时,它会产生以下结果 -
两个数:12, 35中的最小值是 : 12
in和out模式 - 示例2
此过程计算传递值的值的平方。此示例显示了如何使用相同的参数来接受值,然后返回另一个结果。
set serveroutput on size 99999;
declare
a number;
procedure squarenum(x in out number) is
begin
x := x * x;
end;
begin
a:= 11;
squarenum(a);
dbms_output.put_line(' square of (23): ' || a);
end;
/
当上述代码在sql提示符下执行时,它会产生以下结果 -
实际参数(实参)可以通过三种方式传递 -
位置符号
在位置符号中,可以调用存储过程如下 -
findmin(a, b, c, d);
在位置符号中,第一个实际参数代替第一个形式参数; 第二个实际参数代替第二个形式参数,依此类推。 因此,a
代替x
,b
代替y
,c
代替z
,d
代替m
。
命名符号
在命名符号中,实际参数与使用箭头符号(=>
)的形式参数相关联。调用存储过程如下所示 -
findmin(x => a, y => b, z => c, m => d);
混合符号
在混合符号表示中,可以在过程调用中混合使用符号; 然而,位置符号应在命名符号之前。
以下调用存储过程的方式是合法的 -
findmin(a, b, c, m => d);
但是,以下这种是不合法的:
findmin(x => a, b, c, d);