1.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 WHERETYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个TestWINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL+N单步调试
2.关于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
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/48e3d422a0404483a9deefb3128506c9.gif)
3.在利用select...into...语法时,必须先确保数据库中有该条记录,否则会报出"no datafound"异常。
可以在该语法之前,先利用
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的问题
6.Hibernate调用oracle存储过程
this.pnumberManager.getHibernateTemplate().execute(
new HibernateCallback() {
public ObjectdoInHibernate(Session session)
throws HibernateException,SQLException {
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/a346b1749c914b45a8a28b734475a530.gif)
CallableStatementcs = session
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/a346b1749c914b45a8a28b734475a530.gif)
.connection()
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/a346b1749c914b45a8a28b734475a530.gif)
.prepareCall("{callmodifyapppnumber_remain(?)}");
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/a346b1749c914b45a8a28b734475a530.gif)
cs.setString(1,foundationid);
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/a346b1749c914b45a8a28b734475a530.gif)
cs.execute();
return
null;
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/e8445bf7ddf44148ae0f893952078119.gif)
}
![oracle存储过程基础语法+提升+例子总结](http://img.e-com-net.com/image/info5/15af85f0a9eb4593b844790c5822ac1f.gif)
});
3.存储过程中Sequence的使用
Java代码
- create or replace procedure GetRecords(name_out outvarchar2,age_in in varchar2) as
- begin
- select NAME into name_out from test where AGE =age_in;
- end;
- create or replace procedure insertRecord(UserID invarchar2, UserName in varchar2,UserAge in varchar2) is
- begin
- insert into test values (UserID, UserName,UserAge);
- end;
首先,在Oracle中创建了一个名为TEST_SEQ的Sequence对象,SQL语句如下:
Java代码
- create sequence TEST_SEQ
- minvalue 100
- maxvalue 999
- start with 102
- increment by 1
- nocache;
语法应该是比较易懂的,最小最大值分别用minvalue,maxvalue表示,初始值是102(这个数字是动态变化的,我创建的时候设的是100,后因插入了2条数据后就自动增加了2),increment当然就是步长了。在PL/SQL中可以用test_seq.nextval访问下一个序列号,用test_seq.currval访问当前的序列号。
定义完了Sequence,接下来就是创建一个存储过程InsertRecordWithSequence:
--这次我修改了test表的定义,和前面的示例不同。其中,UserID是PK。
Java代码
- create or replace procedureInsertRecordWithSequence(UserID out number,UserName invarchar2,UserAge in number)
- is
- begin insert into test(id, name, age)--插入一条记录,PK值从Sequece获取
- values(test_seq.nextval, UserName, UserAge);
- select test_seq.currval into UserID fromdual;
- end InsertRecordWithSequence;
4.存储过程中包的定义
为了让存储过程返回结果集,必须定义一个游标变量作为输出参数。这和SqlServer中有着很大的不同!并且还要用到Oracle中“包”(Package)的概念,似乎有点繁琐,但熟悉后也会觉得很方便。
关于“包”的概念,有很多内容可以参考,在此就不赘述了。首先,我创建了一个名为TestPackage的包,包头是这么定义的:
Java代码
- create or replace package TestPackage is
- type mycursor is ref cursor; -- 定义游标变量
- procedure GetRecords(ret_cursor out mycursor); --定义过程,用游标变量作为返回参数
- end TestPackage;
- 包体是这么定义的:
- create or replace package body TestPackage is
- procedure GetRecords(ret_cursor out mycursor)as
- begin
- open ret_cursor for select * from test;
- end GetRecords;
- end TestPackage;
小结:
包是Oracle特有的概念,SqlServer中找不到相匹配的东西。在我看来,包有点像VC++的类,包头就是.h文件,包体就是.cpp文件。包头只负责定义,包体则负责具体实现。如果包返回多个游标,则DataReader会按照您向参数集合中添加它们的顺序来访问这些游标,而不是按照它们在过程中出现的顺序来访问。可使用DataReader的NextResult()方法前进到下一个游标。
Java代码
- create or replace package TestPackage is
- type mycursor is ref cursor;
- procedure UpdateRecords(id_in in number,newName invarchar2,newAge in number);
- procedure SelectRecords(ret_cursor outmycursor);
- procedure DeleteRecords(id_in in number);
- procedure InsertRecords(name_in in varchar2, age_in innumber);
- end TestPackage;
包体如下:
Java代码
- create or replace package body TestPackage is
- procedure UpdateRecords(id_in in number, newName invarchar2, newAge in number) as
- begin
- update test set age = newAge, name = newName where id =id_in;
- end UpdateRecords;
- procedure SelectRecords(ret_cursor out mycursor)as
- begin
- open ret_cursor for select * from test;
- end SelectRecords;
- procedure DeleteRecords(id_in in number) as
- begin
- delete from test where id = id_in;
- end DeleteRecords;
- procedure InsertRecords(name_in in varchar2, age_in innumber) as
- begin
- insert into test values (test_seq.nextval, name_in,age_in);
- --test_seq是一个已建的Sequence对象,请参照前面的示例
- end InsertRecords;
- end TestPackage;
TestPackage.SelectRecords
-------------------------------------------------------------------------------------------------------------------------------------------------------------
5.存储过程详细例子
最近换了一个项目组,晕,要写oracle的存储过程,幸亏写过一些db2的存储过程,尚且有些经验,不过oralce的pl/sql不大一样,花费了一下午的时间写了一个出来,测试编译通过了,是为记,以备以后查阅。
Java代码
- CREATE OR REPLACE PACKAGE PY_PCKG_REFUND2AS
- ------------------------------------------------------------------------
- -- Oracle 包
- ---国航支付平台VISA退款
- -- 游标定义:
- --
- -- 存储过程定义:
- -- PY_WEBREFUND_VISA_PREPARE :VISA退款准备
- -- 最后修改人:dougq
- -- 最后修改日期:2007.4.17
- ------------------------------------------------------------------------
- PROCEDURE PY_WEBREFUND_VISA_PREPARE(
- in_serialNoStr IN VARCHAR2,--用"|"隔开的一组网上退款申请流水号
- in_session_operatorid IN VARCHAR2,--业务操作员
- out_return_code OUT VARCHAR2,--存储过程返回码
- out_visaInfoStr OUT VARCHAR2
- );
- END PY_PCKG_REFUND2;
- /
- CREATE OR REPLACE PACKAGE BODY PY_PCKG_REFUND2AS
- PROCEDURE PY_WEBREFUND_VISA_PREPARE(
- in_serialNoStr IN VARCHAR2,--用"|"隔开的一组网上退款申请流水号
- in_session_operatorid INVARCHAR2,--业务操作员
- out_return_code OUT VARCHAR2,--存储过程返回码
- out_visaInfoStr OUT VARCHAR2
- ) IS
- --变量声明
- v_serialno VARCHAR2(20);--网上退款申请流水号
- v_refserialno VARCHAR2(20);--支付交易流水号
- v_tobankOrderNoVARCHAR2(30);--上送银行的订单号
- v_orderDate VARCHAR2(8);--订单日期
- v_businessType VARCHAR2(10);--业务类型
- v_currTypeVARCHAR2(3);--订单类型(ET-电子机票)
- v_merno VARCHAR2(15);--商户号
- v_orderNo VARCHAR2(20);--商户订单号
- v_orderState VARCHAR2(2);
- v_refAmount NUMBER(15,2);--退款金额
- v_tranType VARCHAR(2);--交易类型
- v_bank VARCHAR2(10);--收单银行
- v_date VARCHAR2 (8);--交易日期
- v_time VARCHAR2 (6);--交易时间
- v_datetime VARCHAR2 (14);--获取的系统时间
- v_index_start NUMBER;
- v_index_end NUMBER;
- v_i NUMBER;
- BEGIN
- -- 初始化参数
- out_visaInfoStr := '';
- v_i := 1;
- v_index_start := 1;
- v_index_end :=INSTR(in_serialNoStr,'|',1,1);
- v_refserialno := SUBSTR(in_serialNoStr,v_index_start, v_index_end-1);
- v_datetime := TO_CHAR (SYSDATE,'yyyymmddhh24miss');
- v_date := SUBSTR (v_datetime, 1, 8);
- v_time := SUBSTR (v_datetime, 9,14);
- --从退款请求表中查询定单信息(商户号、商户订单号、退款金额)
- WHILE v_index_end > 0LOOP
- SELECT
- WEBR_MERNO,
- WEBR_ORDERNO,
- WEBR_AMOUNT,
- WEBR_SERIALNO,
- WEBR_REFUNDTYPE
- INTO
- v_merno,
- v_orderNo,
- v_refAmount,
- v_serialno,
- v_tranType
- FROM
- PY_WEB_REFUND
- WHERE
- WEBR_REFREQNO = v_refserialno;
- --将查询到的数据组成串
- out_visaInfoStr := out_visaInfoStr || v_merno ||'~' || v_orderNo || '~' || v_refAmount + '|';
- --为下次循环做数据准备
- v_i := v_i + 1;
- v_index_start := v_index_end + 1;
- v_index_end :=INSTR(in_serialNoStr,'|',1,v_i);
- IF v_index_end > 0THEN
- v_refserialno := SUBSTR(in_serialNoStr,v_index_start, v_index_end - 1);
- END IF;
- --根据原支付流水号在流水表中查询该订单的信息,包括原上送银行或第三方的订单号:WTRN_TOBANKORDERNO
- SELECT
- WTRN_TOBANKORDERNO,
- WTRN_ORDERNO,
- WTRN_ORDERDATE,
- WTRN_BUSINESSTYPE,
- WTRN_ACCPBANK,
- WTRN_TRANCURRTYPE
- INTO
- v_tobankOrderNo,
- v_orderNo,
- v_orderDate,
- v_businessType,
- v_bank,
- v_currType
- FROM PY_WEBPAY_VIEW
- WHERE WTRN_SERIALNO = v_serialno;
- --记录流水表(退款)
- INSERT INTO PY_WEBPAY_TRAN(
- WTRN_SERIALNO,
- WTRN_TRANTYPE,
- WTRN_ORIGSERIALNO,
- WTRN_ORDERNO,
- WTRN_ORDERDATE,
- WTRN_BUSINESSTYPE,
- WTRN_TRANCURRTYPE,
- WTRN_TRANAMOUNT,
- WTRN_ACCPBANK,
- WTRN_TRANSTATE,
- WTRN_TRANTIME,
- WTRN_TRANDATE,
- WTRN_MERNO,
- WTRN_TOBANKORDERNO
- )VALUES(
- v_refserialno, --和申请表的流水号相同,作为参数传人
- v_tranType,
- v_serialno, --原交易流水号,查询退款申请表得到
- v_orderNo,
- v_orderDate,
- v_businessType,
- v_currType,
- v_refAmount,
- v_bank,
- '1',
- v_time,
- v_date,
- v_merno,
- v_tobankOrderNo --上送银行的订单号,查询流水表得到
- );
- --更新网上退款申请表
- UPDATE PY_WEB_REFUND
- SET
- WEBR_IFDISPOSED = '1',
- WEBR_DISPOSEDOPR =in_session_operatorid,
- WEBR_DISPOSEDDATE = v_datetime
- WHERE
- WEBR_REFREQNO = v_refserialno;
- --更新定单表
- IF v_tranType = '2' THEN
- v_orderState := '7';
- ELSE
- v_orderState := '10';
- END IF;
- UPDATE PY_ORDER
- SET
- ORD_ORDERSTATE = v_orderState
- WHERE
- ORD_ORDERNO = v_orderNo
- AND ORD_ORDERDATE = v_orderDate
- AND ORD_BUSINESSTYPE =v_businessType;
- END LOOP;
- -- 异常处理
- EXCEPTION
- WHEN OTHERS THEN
- ROLLBACK;
- out_return_code := '14001';
- RETURN;
- END;
- END PY_PCKG_REFUND2;
- /
6.带游标
cursor
的存储过程详细例子
Sql代码
- --1、简单的存储过程
- create or replaceprocedure procedure_test
- (p_id in varchar,p_statusout varchar) --p_id为输入参数,p_status为输出参数
- as
- t_name varchar2(20);
- t_count number:=0;
- begin
- select votetitle,vatesum intot_name,t_count from votemaster whereid=p_id; --注意:此处没有:来赋值
- if t_count <=0 then
- p_status:= t_name||':差';
- elsif t_count >0 and t_count<3 then
- p_status:= t_name||':良好';
- else
- p_status:= t_name||':优秀';
- end if;
- end;
- --执行
- declare
- out_param varchar2(50);
- begin
- procedure_test('1',out_param);
- dbms_output.put_line(out_param);
- end;
- --2、带游标的存储过程
- create or replaceprocedure procedure_cursor_test
- (p_id in varchar2,p_status outvarchar2)
- as
- vote votemaster%rowtype;--声明一个对象(votemaster)类型的对象
- cursor my_cur is select* from votemaster; --声明一个游标并填充数据
- begin
- open my_cur; --打开游标
- loop
- fetch my_cur into vote ;--循环游标,并放入对象
- exit when my_cur%notfound;--如果没有数据,则直接exit
- if vote.id=p_id then
- p_status :=vote.votetitle||':'||vote.vatesum;
- --如果想终止循环,可以直接exit;
- end if;
- end loop;
- close my_cur; --关闭游标
- end;
- --执行
- declare
- out_param varchar2(50);
- begin
- procedure_cursor_test('1',out_param);
- dbms_output.put_line(out_param);
- end;
7.存储过程中
function使用
详细例子
Sql代码
- --包定义
- create orreplace package t_package
- is
- --定义过程
- procedure append_proc(t varchar2,aout varchar2);
- --过程的重载
- procedure append_proc(t number,aout varchar2);
- --定义函数
- function append_fun(t varchar2)return varchar2;
- end;
Sql代码
- --包主题
- create orreplace package body t_package
- is
- v_t varchar2(30);
- --私有成员函数
- function private_fun(t varchar2)return varchar2 is
- begin
- v_t := t||'hello';
- return v_t;
- end;
- --实现过程
- procedure append_proc(t varchar2,aout varchar2) is
- begin
- a := t||'hello';
- end;
- --过程的重载
- procedure append_proc(t number,aout varchar2) is
- begin
- a := t||'hello';
- end;
- --实现函数
- function append_fun(tvarchar2)
- return varchar2 is
- begin
- v_t := t||'hello';
- return v_t;
- end;
- end;