Oracle之存储过程

一、定义

所谓存储过程(Stored Procedure),就是一组用于完成特定数据库功能的SQL语句集,该SQL语句集通过编译后存储在数据库系统中。在使用时候,用户经过指定已经定义的存储过程名字并给出相应的存储过程参数来调用并执行它,从而完成一个或一系列的数据库操做。node

二、存储过程的建立

Oracle存储过程包含三部分:过程声明,执行过程部分,存储过程异常。sql

(1)无参存储过程语法

create or replace procedure NoParPro  数据库

as //声明  session

oracle

begin // 执行  app

函数

exception//存储过程异常  fetch

this

end;命令行

(2)带参存储过程实例

create or replace procedure queryempname(sfindno emp.empno%type)  

as

sName emp.ename%type; 

sjob emp.job%type; 

begin

.... 

exception 

.... 

end;

(3)带参数存储过程含赋值方式
create or replace procedure runbyparmeters   

(isal in emp.sal%type,  

sname out varchar

sjob in out varchar

as

icount number; 

begin

select count(*) into icount from emp where sal>isal and job=sjob; 

if icount=1 then

.... 

else

.... 

end if; 

exception 

when too_many_rows then

DBMS_OUTPUT.PUT_LINE('返回值多于1行'); 

when others then

DBMS_OUTPUT.PUT_LINE('在RUNBYPARMETERS过程当中出错!'); 

end;

其中参数IN表示输入参数,是参数的默认模式。

OUT表示返回值参数,类型可使用任意Oracle中的合法类型。

OUT模式定义的参数只能在过程体内部赋值,表示该参数能够将某个值传递回调用他的过程

IN OUT表示该参数能够向该过程当中传递值,也能够将某个值传出去。

(4)存储过程当中游标定义使用

as //定义(游标一个能够遍历的结果集)  

CURSOR cur_1 IS

SELECT area_code,CMCODE,SUM(rmb_amt)/10000 rmb_amt_sn, 

SUM(usd_amt)/10000 usd_amt_sn  

FROM BGD_AREA_CM_M_BASE_T  

WHERE ym >= vs_ym_sn_beg  

AND ym <= vs_ym_sn_end  

GROUP BY area_code,CMCODE;  

begin //执行(经常使用For语句遍历游标)      

FOR rec IN cur_1 LOOP  

UPDATE xxxxxxxxxxx_T  

SET rmb_amt_sn = rec.rmb_amt_sn,usd_amt_sn = rec.usd_amt_sn  

WHERE area_code = rec.area_code  

AND CMCODE = rec.CMCODE  

AND ym = is_ym;  

END LOOP;

(5)游标的定义

--显示cursor的处理

declare

---声明cursor,建立和命名一个sql工做区

cursor cursor_name is

select real_name from account_hcz;

v_realname varchar2(20);

begin

open cursor_name;---打开cursor,执行sql语句产生的结果集

fetch cursor_name into v_realname;--提取cursor,提取结果集中的记录

dbms_output.put_line(v_realname);

close cursor_name;--关闭cursor

end;

三、在Oracle中对存储过程的调用

(1)过程调用方式一

declare

realsal emp.sal%type; 

realname varchar(40); 

realjob varchar(40); 

begin //过程调用开始 

realsal:=1100; 

realname:=''

realjob:='CLERK'

runbyparmeters(realsal,realname,realjob);--必须按顺序 

DBMS_OUTPUT.PUT_LINE(REALNAME||'   '||REALJOB); 

END;  //过程调用结束

(2)过程调用方式二

declare

realsal emp.sal%type; 

realname varchar(40); 

realjob varchar(40); 

begin //过程调用开始 

realsal:=1100; 

realname:=''

realjob:='CLERK'

--指定值对应变量顺序可变 

runbyparmeters(sname=>realname,isal=>realsal,sjob=>realjob);          

DBMS_OUTPUT.PUT_LINE(REALNAME||'   '||REALJOB); 

END;  //过程调用结束

(3)过程调用方式三(SQL命令行方式下)

一、SQL>exec proc_emp(‘参数1’,’参数2’);//无返回值过程调用

二、SQL>var vsal number

SQL> exec proc_emp (‘参数1’,:vsal);// 有返回值过程调用

或者:call proc_emp (‘参数1’,:vsal);// 有返回值过程调用

存储过程建立语法

create [or replace] procedure 存储过程名(param1 in type,param2 out type)

as

变量1 类型(值范围);

变量2 类型(值范围);

Begin

Select count(*) into 变量1 from 表A where列名=param1;

If (判断条件) then

Select 列名 into 变量2 from 表A where列名=param1;

Dbms_output.Put_line(‘打印信息’);

Elsif (判断条件) then

Dbms_output.Put_line(‘打印信息’);

Else

Raise 异常名(NO_DATA_FOUND);

End if;

Exception

When others then

Rollback;

End;

注意事项

存储过程参数不带取值范围,in表示传入,out表示输出; 变量带取值范围,后面接分号; 在判断语句前最好先用count(*)函数判断是否存在该条操做记录; 用select … into … 给变量赋值; 在代码中抛异经常使用 raise+异常名;

已命名的异常

命名的系统异常 产生缘由


ACCESS_INTO_NULL 未定义对象 CASE_NOT_FOUND CASE 中若未包含相应的 WHEN ,而且没有设置ELSE 时 COLLECTION_IS_NULL 集合元素未初始化 CURSER_ALREADY_OPEN 游标已经打开 DUP_VAL_ON_INDEX 惟一索引对应的列上有重复的值 INVALID_CURSOR 在不合法的游标上进行操做 INVALID_NUMBER 内嵌的 SQL 语句不能将字符转换为数字 NO_DATA_FOUND 使用 select into 未返回行,或应用索引表未初始化的 TOO_MANY_ROWS 执行 select into 时,结果集超过一行 ZERO_DIVIDE 除数为 0 SUBSCRIPT_BEYOND_COUNT 元素下标超过嵌套表或 VARRAY 的最大值 SUBSCRIPT_OUTSIDE_LIMIT 使用嵌套表或 VARRAY 时,将下标指定为负数 VALUE_ERROR 赋值时,变量长度不足以容纳实际数据 LOGIN_DENIED PL/SQL 应用程序链接到 oracle 数据库时,提供了不正确的用户名或密码 NOT_LOGGED_ON PL/SQL 应用程序在没有链接 oralce 数据库的状况下访问数据 PROGRAM_ERROR PL/SQL 内部问题,可能须要重装数据字典& pl./SQL系统包 ROWTYPE_MISMATCH 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容 SELF_IS_NULL 使用对象类型时,在 null 对象上调用对象方法 STORAGE_ERROR 运行 PL/SQL 时,超出内存空间 SYS_INVALID_ID 无效的 ROWID 字符串 TIMEOUT_ON_RESOURCE Oracle 在等待资源时超时

基本语法

1. 基本结构

CREATE OR REPLACE PROCEDURE 存储过程名字

(

参数1 IN NUMBER,

参数2 IN NUMBER

) IS

变量1 INTEGER :=0;

变量2 DATE;

BEGIN

--执行体

END 存储过程名字;

2. SELECT INTO STATEMENT

将select查询的结果存入到变量中,能够同时将多个列存储多个变量中,必须有一条记录,不然抛出异常(若是没有记录抛出NO_DATA_FOUND)

例子:

BEGIN

SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;

EXCEPTION

WHEN NO_DATA_FOUND THEN

xxxx;

END;

3. IF 判断

IF V_TEST = 1 THEN

BEGIN

do something

END;

END IF;

4. while 循环

WHILE V_TEST=1 LOOP

BEGIN

XXXX

END;

END LOOP;

5. 变量赋值

V_TEST := 123;

6. 用for in 使用cursor

IS

CURSOR cur IS SELECT * FROM xxx;

BEGIN

FOR cur_result in cur LOOP

BEGIN

V_SUM :=cur_result.列名1+cur_result.列名2

END;

END LOOP;

END;

7. 带参数的cursor

CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;

OPEN C_USER(变量值);

FETCH C_USER INTO V_NAME;

EXIT WHEN FETCH C_USER%NOTFOUND;

CLOSE C_USER;

8. 用pl/sql developer debug

链接数据库后创建一个Test WINDOW,在窗口输入调用SP的代码,F9开始debug,CTRL+N单步调试

关于oracle存储过程的若干问题备忘

1.在oracle中,数据表别名不能加as,如:

select a.appname from appinfo a;-- 正确

select a.appname from appinfo as a;-- 错误

也许,是怕和oracle中的存储过程当中的关键字as冲突的问题吧

2.在存储过程当中,select某一字段时,后面必须紧跟into,若是select整个记录,利用游标的话就另当别论了。

select af.keynode into kn from APPFOUNDATION af

where af.appid=aid and af.foundationid=fid;-- 有into,正确编译

select af.keynode from APPFOUNDATION af

where af.appid=aid and af.foundationid=fid;-- 没有into,编译报错,提示:Compilation Error: PLS-00428: an INTO clause is expected in this SELECT statement

3.在利用select…into…语法时,必须先确保数据库中有该条记录,不然会报出”no data found”异常。

能够在该语法以前,先利用select count(*) from 查看数据库中是否存在该记录,若是存在,再利用select…into…

4.在存储过程当中,别名不能和字段名称相同,不然虽然编译能够经过,但在运行阶段会报错

--正确

select keynode into kn from APPFOUNDATION where appid=aid and foundationid=fid;

--错误

select af.keynode into kn from APPFOUNDATION af

where af.appid=appid and af.foundationid=foundationid;

-- 运行阶段报错,提示ORA-01422:exact fetch returns more than requested number of rows

5.在存储过程当中,关于出现null的问题

假设有一个表A,定义以下:

create table A(

id varchar2(50) primary key not null,

vcount number(8) not null,

bid varchar2(50) not null -- 外键

);

若是在存储过程当中,使用以下语句:

select sum(vcount) into fcount from A where bid='xxxxxx';

若是A表中不存在bid=”xxxxxx”的记录,则fcount=null(即便fcount定义时设置了默认值,如:fcount number(8):=0依然无效,fcount仍是会变成null),这样之后使用fcount时就可能有问题,因此在这里最好先判断一下:

if fcount is null then

fcount:=0;

end if;

这样就一切ok了。

6.Hibernate调用oracle存储过程

this.pnumberManager.getHibernateTemplate().execute(

new HibernateCallback() {

public Object doInHibernate(Session session)

throws HibernateException, SQLException {

CallableStatement cs = session

.connection()

.prepareCall("{call modifyapppnumber_remain(?)}");

cs.setString(1, foundationid);

cs.execute();

return null;

}

});

相关文章
相关标签/搜索