子程序可以带有参数,参数可以具有不同的模式,可以按值传递,也可以通过引用传递。
形参与实参
形式参数:子定义子程序时,在定义语句中定义的参数称为形式参数,简称形参。形参的数据类型不包含任何的长度约束。通常使用p开头作为形参的前缀,如p_deptno
。
实际参数:在调用子程序时,传入的具体参数值称为实际参数,简称实参。实参和它对应的形参必须类型兼容。
参数模式
形参的模式用来控制形参的行为,有3中模式:IN,OUT,IN OUT。如果没有指定,默认为IN。
IN模式的参数称为输入参数,它就像常量一样,不能被赋值。
OUT模式的参数称为输出参数,输出参数将会改变参数的值,因此实参不能用固定字符串或常量来传递,必须是一个变量。
OUT模式的形参会被初始化为NULL,所以形参的数据类型是不能有NOT NULL约束的。
IN OUT模式又称为输入/输出参数,形参可以被读出和写入。他的实参也必须是一个变量,不可以是常量或表达式。如果成功地退出子程序,PL/SQL就会为实参赋值,如果有未捕获的异常发生,PL/SQL就不会为实参赋值。
形参的约束
在子程序定义时,形参不能指定长度的约束,任何指定长度或精度的约束都是不合法的。如:
CREATE OR REPLACE PROCEDURE calcSalary(
p_job IN VARCHAR2(10),
p_salary IN OUT NUMBER(10,2))
AS
BEGIN
...
END;
这样是错误的,PL/SQL引擎将抛出编译时错误,必须要去掉对形参中的长度约束。
实际上形参的约束来自于实参,传入的实参具有怎样的长度约束,形参就具有怎样的长度约束。
虽然形参不能用约束声明,但是可以使用%TYPE对其进行约束。如果形参使用了%TYPE进行声明,那么其潜在类型是收到约束的。
参数传递方式
有两种向子程序传递参数的方式:一种是前面见过的按位置传递,另一种是按名称传递。
大多参数传递的场合都是用按位置传递方式,只要传入的实参的位置匹配形参的位置定义即可。如:
calcSalary(v_job,v_sal);
按名称传递是使用=>
作为关联的操作符,如:
calcSalary(p_job=>v_job,p_salary=>v_sal);
由于使用了名字进行标识,因此参数的位置就不重要了,这样的写法和上面实际上是一样的:
calcSalary(p_salary=>v_sal,p_job=>v_job);
还可以混合使用按位置传递和按名称传递,但是在这种情况下,位置标识法必须在名称标识法之前。
参数默认值
在定义子程序时,可以使用 DEFAULT关键字或赋值语句为IN模式的参数指定默认值。
CREATE OR REPLACE PROCEDURE newdeptwithdefault (
p_deptno dept.deptno%TYPE DEFAULT 57, --部门编号
p_dname dept.dname%TYPE:='管理部', --部门名称
p_loc dept.loc%TYPE DEFAULT '江苏' --位置
)
AS
BEGIN
...
END;
BEGIN
newdeptwithdefault; --不指定任何参数,将使用形参默认值
END;
BEGIN
newdeptwithdefault(58,'事务组'); --p_loc使用默认值
END;
BEGIN
newdeptwithdefault(p_deptno=>58, p_loc=>'南海'); --p_dname使用默认值
END;
使用NOCOPY编译提示
首先需要理解引用传递和值传递之间的区别。
值传递:当参数通过值传递时,参数将从实际参数中被复制到形式参数中。
引用传递:实际参数的指针被传递到了相应的形式参数中。
默认情况下,PL/SQL通过引用来传递IN参数,引用传递速度快,因为仅实际参数的指针传递到相应的形式参数中,不需要进行复制,这对于占用空间较大的参数,比如集合类型具有较高的效率。而IN OUT参数和OUT参数通过值进行传递,这主要是因为对实际参数的约束可以被校验,当子程序正常结束后,被赋到OUT和IN OUT形参上的值就会复制到对应的实参上。
在使用OUT和IN OUT参数时,如果参数是大型数据结构,比如集合、记录、对象实例,可以使用NOCOPY编译提示按引用进行传递:
parameter_name [mode] NOCOPY datatype
如:
CREATE OR REPLACE PROCEDURE NoCopyDemo
(
p_InParam IN NUMBER,
p_InOutParam IN OUT NOCOPY VARCHAR2,
p_OutParam OUT NOCOPY VARCHAR2
)
IS
...