CREATE PROCEDURE
名称
CREATE PROCEDURE —— 定义一个新的存储过程。执行此操作之前,要先设置将 PLSQL_MODE 打开,创建好存储过程后,再把此参数设置为 OFF,否则,事务不会自动提交,命令“/”可以提交事务。方法如下:
\set PLSQL_MODE ON
\set PLSQL_MODE OFF
概要
CREATE [ OR REPLACE ] PROCEDURE name
([argname [ IN | IN OUT | OUT ] argtype [ DEFAULT value ]
[, ...] ] )
{ IS | AS }
[ declaration; ] [, ...]
BEGIN
statement; [...]
[ EXCEPTION
{ WHEN exception [ OR exception ] [...] THEN
statement; [, ...] } [, ...]
]
END [ name ]
描述
CREATE PROCEDURE 命令定义一个新的存储过程。CREATE OR REPLACE PROCEDURE 命令既可以创建一个新的存储过程,也可以用新创建的存储过程定义替代已存在的存储过程定义。如果包含了模式的名称,那么存储过程是在指定模式下创建,否则就是在当前模式下创建。新的存储过程名不应与同一模式下任何存储过程的名称相同。除非打算使用 CREATE OR REPLACE PROCEDURE 命令更新一个已存在存储过程的定义。
创建存储过程的用户是新创建存储过程的所有者。
关于存储过程的更多内容参见章节 3。
参数
name
所创建存储过程的名称(可以采用模式限定的方式引用)。
argname
参数的名称。参数是通过在存储过程体内部的名称来引用的。
IN | IN OUT | OUT
参数模式。IN 将参数声明为输入参数。这是缺省的情况。IN OUT 允许参数既可以接收值,也可以返回值。 OUT 指定参数只是用作输出。
argtype
存储过程参数的数据类型。参数类型可以是基本数据类型,使用 %TYPE 作为数据类型的已存在列的拷贝,或者一个用户定义类型,比如嵌套表或者一个对象类型。对于任何基础数据类型来说,不应该指定长度-例如,指定 VARCHAR2,而不是 VARCHAR2(10)。
通过使用 tablename.columnname%TYPE,可以引用一个列的类型。当表的定义发生改变的时候,使用这种方式可以不用修改存储过程的主体。
DEFAULT value
当调用存储过程的时候没有为参数提供值时,它可以为输入参数提供一个缺省值。对于模式为 IN OUT 或者 OUT 的参数来说,不指定参数 DEFAULT。
DEFINER | CURRENT_USER
用来指定是否能使用存储过程所有者(DEFINER)或者当前执行存储过程的用户(CURRENT_USER)的权限来确定是否允许访问在存储过程中引用的数据库对象。在存储过程所有者(DEFINER)这种情况下,使用存储过程所有者的搜索路径来解析对非限定的数据库对象的引用。同时,在当前执行存储过程的用户(CURRENT_USER)这种情况下,使用当前正在执行存储过程用户的搜索路径来解析对非限定数据库对象的引用。DEFINER 是缺省选项。
declaration
变量,类型或者是 REF CURSOR 的声明。
statement
SPL 程序语句。需要注意的是一个 DECLARE-BEGIN-END 的代码块本身就被认为是一条 SPL 语句。因此,函数体内部可以包含嵌套代码块。
exception
异常条件的名称,例如 NO_DATA_FOUND,OTHERS 等等。
示例
下面这个存储过程列出了表 emp 中的雇员( emp 表格定义见【示例参考表格】):
\set PLSQL_MODE ON CREATE OR REPLACE PROCEDURE list_emp() IS v_empno NUMBER(4); v_ename VARCHAR2(10); CURSOR emp_cur IS SELECT empno, ename FROM emp ORDER BY empno; BEGIN OPEN emp_cur; DBMS_OUTPUT.PUT_LINE('EMPNO ENAME'); DBMS_OUTPUT.PUT_LINE('----- -------'); LOOP FETCH emp_cur INTO v_empno, v_ename; EXIT WHEN emp_cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename); END LOOP; CLOSE emp_cur; END; / \set PLSQL_MODE OFF SELECT list_emp(); NOTICE: 7369 SMITH NOTICE: 7499 ALLEN NOTICE: 7521 WARD NOTICE: 7566 JONES NOTICE: 7654 MARTIN NOTICE: 7698 BLAKE NOTICE: 7782 CLARK NOTICE: 7788 SCOTT NOTICE: 7839 KING NOTICE: 7844 TURNER NOTICE: 7876 ADAMS NOTICE: 7900 JAMES NOTICE: 7902 FORD NOTICE: 7934 MILLER LIST_EMP ---------- (1 row)
复制
下面这个存储过程首先根据雇员编号查询雇员编号,雇员姓名和工作种类,如果没有找到结果,那么使用雇员名称查询,最后使用 IN OUT 参数和 OUT 参数将结果返回。这个存储过程是在一个匿名代码块中调用的。
注意,下面的例子中,emp_job 的最后一个参数是输出,在 Oracle 中,可以通过 emp_job(v_empno,v_ename, v_job) 将结果直接赋给 v_job 变量。但是在 AntDB 中,调用存储过程的时候,结果变量不能放在参数中,只能通过这样的方式调用:re= emp_job(v_empno, v_ename);再从 re 中将结果提取出来( emp 表格定义见【示例参考表格】)。
\set PLSQL_MODE ON CREATE OR REPLACE PROCEDURE emp_job ( p_empno IN OUT numeric, p_ename IN OUT varchar2, p_job OUT varchar2 ) IS v_empno emp.empno%TYPE; --函数参数不支持此种格式的定义 v_ename emp.ename%TYPE; v_job emp.job%TYPE; BEGIN SELECT ename, job INTO v_ename, v_job FROM emp WHERE empno = p_empno; p_ename := v_ename; p_job := v_job; DBMS_OUTPUT.PUT_LINE('Found employee # ' || p_empno); EXCEPTION WHEN NO_DATA_FOUND THEN BEGIN SELECT empno, job INTO v_empno, v_job FROM emp WHERE ename = p_ename; p_empno := v_empno; p_job := v_job; DBMS_OUTPUT.PUT_LINE('Found employee ' || p_ename); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Could not find an employee with ' || 'number, ' || p_empno || ' nor name, ' || p_ename); p_empno := NULL; p_ename := NULL; p_job := NULL; END; END; / DECLARE v_empno emp.empno%TYPE; v_ename emp.ename%TYPE; v_job emp.job%TYPE; re record; BEGIN v_empno := 7782; v_ename := 'CLARK'; re := emp_job(v_empno, v_ename); DBMS_OUTPUT.PUT_LINE('Employee No: ' || v_empno); DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename); DBMS_OUTPUT.PUT_LINE('Job : ' || re.p_job); END; / \set PLSQL_MODE OFF Found employee CLARK Employee No: 7782 Name : CLARK Job : MANAGER
复制