Oracle 存储过程 使用示例

因为工作的需要,最近一直在写存储过程。 工作了3年,一直都是做管理,也没有正儿八经的去写过存储过程, 这次正好可以好好练习一下。

在这里说一条使用存储过程很重要的理由:存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。

Oracle 存储过程 定义 优点 函数 区别

http://blog.youkuaiyun.com/tianlesoftware/archive/2010/01/27/5261364.aspx

Oracle 查看 存储过程 触发器 函数 等对象定义语句的方法

http://blog.youkuaiyun.com/tianlesoftware/archive/2010/06/19/5679293.aspx

1. 存储过程格式

/* Formatted on 2011/1/17 13:20:44 (QP5 v5.115.810.9015) */

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

)

2. 存储过程中的循环

存储过程写的是业务逻辑,循环是常用的处理方法之一。

2.1 for ... in ... loop 循环

2.1.1:循环遍历游标

示例1

CREATE OR REPLACE PROCEDURE proc_test

AS

CURSOR c1

IS

SELECT * FROM dat_trade;

BEGIN

FOR x IN c1

LOOP

DBMS_OUTPUT.put_line (x.id);

END LOOP;

END proc_test;

示例2

CREATE OR REPLACE PROCEDURE proc_test

AS

BEGIN

FOR x IN (SELECT power_id FROM sys_power)

LOOP

DBMS_OUTPUT.put_line (x.power_id);

END LOOP;

END proc_test;

2.1. 2:根据数值进行循环

示例1

CREATE OR REPLACE PROCEDURE proc_test (v_num IN NUMBER)

AS

BEGIN

for x in 1..100 loop

dbms_output.put_line(x);

end loop;

END proc_test;

示例2:在过程里指定输入参数v_num. 在调用过程时指定循环次数。

CREATE OR REPLACE PROCEDURE proc_test (v_num IN NUMBER)

AS

BEGIN

FOR x IN 1 .. v_num

LOOP

DBMS_OUTPUT.put_line (x);

END LOOP;

END proc_test;

2.2 loop 循环

LOOP

DELETE FROM orders

WHERE senddate < TO_CHAR (ADD_MONTHS (SYSDATE, -3),

'yyyy-mm-dd')

AND ROWNUM < 1000;

EXIT WHEN SQL%ROWCOUNT < 1;

COMMIT;

END LOOP;

这里的SQL%ROWCOUNT 是隐士游标。 除了这个,还有其他几个:%found%notfound %isopen

2.3 while 循环

CREATE OR REPLACE PROCEDURE proc_test (v_num IN NUMBER)

AS

i NUMBER := 1;

BEGIN

WHILE i < v_num

LOOP

BEGIN

i := i + 1;

DBMS_OUTPUT.put_line (i);

END;

END LOOP;

END proc_test;

3. 存储过程中的判断

判断也是存储过程中最常用的方法之一。

3.1 if ... elsif ... else ... 判断

CREATE OR REPLACE PROCEDURE proc_test (v_num IN NUMBER)

AS

BEGIN

IF v_num < 10

THEN

DBMS_OUTPUT.put_line (v_num);

ELSIF v_num > 10 AND v_num < 50

THEN

DBMS_OUTPUT.put_line (v_num - 10);

ELSE

DBMS_OUTPUT.put_line (v_num - 50);

END IF;

END proc_test;

3.2 case ... when ... end case 判断

CREATE OR REPLACE PROCEDURE proc_test (v_num IN NUMBER)

AS

BEGIN

case v_num

when 1 then

DBMS_OUTPUT.put_line (v_num);

when 2 then

DBMS_OUTPUT.put_line (v_num);

when 3 then

DBMS_OUTPUT.put_line (v_num);

else null;

end case;

END proc_test;

4. 游标

存储过程中使用游标也是很常见的。 这里的游标分两种:

4.1 Cursor型游标(不能用于参数传递)

这种方法具体参考 2.1.1:循环遍历游标 中的示例。

4.2 SYS_REFCURSOR型游标

该游标是Oracle以预先定义的游标,可作出参数进行传递。

注意一点:SYS_REFCURSOR只能通过OPEN方法来打开和赋值

4.2.1 我们可以使用这种类似的游标来返回一个结果集:

CREATE OR REPLACE procedure proc_test(

checknum in number, --每次返回的数据量

ref_cursor out sys_refcursor --返回的结果集,游标

)

as

begin

open ref_cursor for select * from (select * from dat_trade where state=41 order by id) where rownum<checknum;

end proc_test;

/

SYS_REFCURSOR中可使用三个状态属性:

(1). %NOTFOUND(未找到记录信息)

(2). %FOUND(找到记录信息)

(3). %ROWCOUNT(然后当前游标所指向的行位置)

CREATE OR REPLACE PROCEDURE proc_test (

checknum IN NUMBER, --每次返回的数据量

ref_cursor OUT sys_refcursor --返回的结果集,游标

)

AS

t_tmp table_name%ROWTYPE;

BEGIN

OPEN ref_cursor FOR

SELECT *

FROM ( SELECT *

FROM table_name

WHERE state = 41

ORDER BY id)

WHERE ROWNUM < checknum;

--循环游标

LOOP

FETCH ref_cursor INTO t_tmp;

EXIT WHEN ref_cursor%NOTFOUND;

-- DBMS_OUTPUT.put_line (t_tmp.id);

UPDATE table_name

SET state = 53

WHERE id = t_tmp.id;

COMMIT;

END LOOP;

CLOSE ref_cursor;

END proc_test;

. 存储过程的调试

如果使用PL/SQL Developer 或者TOAD 工具的话,调试还是很方便的。 如果是在Sqlplus里,我们可以使用:

SQL>show errors

来查看错误。不过在开发中估计也很少有人直接使用sqlplus来写存储过程。 效率低,调试又麻烦。 还是使用工具方便点。我一直使用的是Toad的。

如果想在某处退出存储过程,直接使用Return;就可以了。 与存储过程编写相关的数组和游标, 这两块说起来还是有很多东西。 在上面的示例中, 也简单的举了几个有关游标与存储过程编写的例子。

总之,写代码都是都是费脑子的事,相比之下还是做管理DBA舒服点,虽然压力大很多,至少不用这么费心思去整理业务逻辑。

------------------------------------------------------------------------------

Blog http://blog.youkuaiyun.com/tianlesoftware

网上资源: http://tianlesoftware.download.youkuaiyun.com

相关视频:http://blog.youkuaiyun.com/tianlesoftware/archive/2009/11/27/4886500.aspx

DBA1 群:62697716(); DBA2 群:62697977()

DBA3 群:62697850 DBA 超级群:63306533;

聊天 群:40132017

--加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值