1.6.1 Procedure 定义
1.6.1.1 定义
存储过程(Stored Procedure )是一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。 存储过程是由流控制和 SQL 语句书写的过程,这个过程经编译和优化后存储在数据库服务器中,应用程序使用时只要调用即可。在ORACLE 中,若干个有联系的过程可以组合在一起构成程序包。
1.6.1.2 优 点
1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度
2.当对数据库进行复杂操作时(如对多个表进行 Update、Insert、Query、Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
3.存储过程可以重复使用,可减少数据库开发人员的工作量。
4.安全性高,可设定只有某用户才具有对指定存储过程的使用权。
1.6.1.3 存储过程与函数的对比
存储过程 |
函 数 |
作为 PL/SQL 语句执行 |
作为表达式的一部分调用 |
在规格说明中不包含 RETURN 子句 |
必须在规格说明中包含 RETURN 子句 |
不返回任何值 |
必须返回单个值 |
可以包含 RETURN 语句,但是与函数不同,它不能用于返回值 |
必须包含至少一条 RETURN |
1.6.2 存储过程使用示例
1.6.2.1. 存储过程格式
创建过程的语法:
CREATE [OR REPLACE] PROCEDURE
<procedure name> [(<parameter list>)]
IS|AS
<local variable declaration>
BEGIN
<executable statements>
[EXCEPTION
<exception handlers>]
END;
例如:
CREATE OR REPLACE PROCEDURE
find_emp(emp_no NUMBER)
AS
empname VARCHAR2(20);
BEGIN
SELECT ename INTO empname
FROM EMP WHERE empno = emp_no;
DBMS_OUTPUT.PUT_LINE('雇员姓名是 '|| empname);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('雇员编号未找到');
END find_emp;
/
CREATE OR REPLACE procedure proc_trade(
v_tradeid in number, --交易id
v_third_ip in varchar2, --第三方ip
v_third_time in date , --第三方完成时间
v_thire_state in number , --第三方状态
o_result out number, --返回值
o_detail out varchar2 --详细描述
)
as
-- 定义变量
v_error varchar2(500);
begin
--对变量赋值
o_result:=0;
o_detail:='验证失败';
--业务逻辑处理
if v_tradeid >100 then
insert into table_name(...) values(...);
commit;
elsif v_tradeid < 100 and v_tradeid>50 then
insert into table_name(...) values(...);
commit;
else
goto log;
end if;
--跳转标志符,名称自己指定
<<log>>
o_result:=1;
--捕获异常
exception
when no_data_found
then
result := 2;
when dup_val_on_index
then
result := 3;
when others
then
result := -1;
end proc_trade;
在上面这个存储过程中使用了输入参数,并返回输出参数,这里的参数类型是我们自己指定的。 这种写法可行,但是最好使用%type 来获取参数的类型(table_name.column_name%TYPE)。 这样就不会出现参数类型的错误。 如:
CREATE OR REPLACE PROCEDURE spdispsms (
aempid IN otherinfo.empid%TYPE,
amsg IN otherinfo.msg%TYPE,
abillno IN otherinfo.billno%TYPE,
ainfotype IN otherinfo.infotype%TYPE,
aopid IN otherinfo.OPERATOR%TYPE,
ainfoid OUT otherinfo.infoid%TYPE,
RESULT OUT INTEGER
)
过程参数的三种模式:
IN
用于接受调用程序的值
默认的参数模式
OUT
用于向调用程序返回值
IN OUT
用于接受调用程序的值,并向调用程序返回更新的值
IN参数过程:
create or replace procedure proc1(i in number)
as
a varchar2(40);
begin
a := '';
for j in 1..i loop
a := a ||'*';
dbms_output.put_line(a);
end loop;
end;
/
dbms_output.put_line是自带的函数命令 。
在PL/SQL程序块中: dbms_output.put_line(a);
在PL/SQL语句中: exec dbms_output.put_line('你好')
执行过程的语法
EXECUTE procedure_name(parameters_list);
SQL> exec proc1(6)
如果不显示。可能是未打开输出开关: SQL> set serverout on
OUT参数
proc2只能在pl/sql程序段中调用
OUT参数:
ceate or replace procedure proc2(j out int)
as
begin
j := 100;
dbms_output.put_line(j);
end;
/SQL> exec proc2(3);
BEGIN proc2(3); END;*
ERROR at line 1:
ORA-06550: line 1, column 13:
PLS-00363: expression '3' cannot be used as an assignment target
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored表达式3不能用作赋值目标
执行完后执行下面
declare
k number;
begin
proc2(k);
end;
/
IN/OUT类型存储过程:
create or replace procedure proc3(p1 in out number,p2 in out number)
is
v_temp number;
begin
v_temp :=p1;
p1 := p2;
p2 := v_temp;
end;
/
declare
num1 number := 100;
num2 number := 200;
begin
proc3(num1,num2);
dbms_output.put_line('num1=' || num1);
dbms_output.put_line('num2=' || num2);
end;
/
将过程的执行权限授予其他用户:
SQL> GRANT EXECUTE ON find_emp TO MARTIN;
SQL> GRANT EXECUTE ON swap(存储过程名) TO PUBLIC;
删除过程:
SQL> DROP PROCEDURE find_emp;
函数:
函数是可以返回值的命名的 PL/SQL 子程序。
创建函数的语法:
CREATE [OR REPLACE] FUNCTION
<function name> [(param1,param2)]
RETURN <datatype> IS|AS
[local declarations]
BEGIN
Executable Statements;
RETURN result;
EXCEPTION
Exception handlers;
END;定义函数的限制:
函数只能接受 IN 参数,而不能接受 IN OUT 或 OUT 参数
形参不能是 PL/SQL 类型,只能是数据库类型
函数的返回类型也必须是数据库类型
访问函数的两种方式:
使用 PL/SQL 块
使用 SQL 语句创建函数
create or replace function fun_hello return varchar2
is
begin
return 'nihao,friend';
end;
/
从 SQL 语句调用函数:
SQL> SELECT fun_hello FROM DUAL;PL/SQL语句中调用:
declare
ss varchar2(20);
begin
ss := fun_hello;
dbms_output.put_line(ss);
end;
/
create table score (student_no number(3),name varchar2(10),score number(3));
insert into score values(1,'张一', 56);
insert into score values(2,'张二', 82);
insert into score values (3,'张三', 90);
要求:创建一个函数,可以接受用户输入的学号,得到该学生的名次,并输出这个名次。
create or replace function func1(sno1 int)
return int
is
score1 number;
mingcil number;
begin
select score into score1 from 分数表 where student_no=sno1;
select count(*) into mingcil from 分数表 where score > score1;
mingcil := mingcil +1;
return mingcil;
end;
/
Warning: Function created with compilation errors. 警告:创建的函数带有编译错误。
演示下如何查看编译错误
SQL> show error
SQL> ed
自主事务处理
主事务处理启动独立事务处理
然后主事务处理被暂停
自主事务处理子程序内的 SQL 操作
然后终止自主事务处理
恢复主事务处理
PRAGMA AUTONOMOUS_TRANSACTION 用于标记子程序为自主事务处理
自主事务处理的特征:
与主事务处理的状态无关
提交或回滚操作不影响主事务处理
自主事务处理的结果对其他事务是可见的
能够启动其他自主事务处理
1.6.2.2. 存储过程中的循环
存储过程写的是业务逻辑,循环是常用的处理方法之一。
1.6.2.2.1 for ... in ... loop 循环
1:循环遍历游标
示例1: