1、存儲過程簡單實例
CREATE OR REPLACE PROCEDURE 存儲過程名稱 (參數in,參數out)
AS
-- 變量聲明,每個聲明用分號結束。可以在聲明的同時初始化
name varchar2(50);
age number(8) default 0;
--開始邏輯運算
BEGIN
--業務邏輯
END
2.游標實現方式
顯式游標實現方式(可多值)
cursor cursorVar is select event_id, isagain, rate from call_event where sender = v_sender; -- 聲明游標,select語句可以包括單引號等。
begin
open cursorVar; -- 打開游標
loop
fetch cursorVar into v_event_id, v_isagain, v_rate; -- 取值
exit when cursorVar%notfound; --當沒有記錄時退出循環
dbms_output.put_line(v_event_id || ', ' || v_isagain || ', ' || v_rate);
end loop;
close cursorVar; -- 關閉游標
游標的屬性有:%FOUND,%NOTFOUNRD,%ISOPEN,%ROWCOUNT;
--%FOUND:已檢索到記錄時,返回true
--%NOTFOUNRD:檢索不到記錄時,返回true
--%ISOPEN:游標已打開時返回true
--%ROWCOUNT:代表檢索的記錄數,從1開始
end;
隱式游標(可以實現查詢多值)
for currow in (
select t.col1, t.col2
from tableName t
where ...
) loop
if currow.col1 = 0 then
return; -- 中止sp,返回
end if;
end loop;
帶有參數的游標(可實現查詢多值)
declare
isok integer;
v_event_id number(10);
v_isagain number(2);
v_rate number(2);
v_sender char(11) := '13800138000';
cursor cursorVar(p_sender varchar2) is select event_id, isagain, rate from call_event where sender = p_sender; -- 聲明游標
begin
open cursorVar(v_sender); -- 打開游標,在括號里傳參。
loop
fetch cursorVar into v_event_id, v_isagain, v_rate; -- 取值
exit when cursorVar%notfound; --當沒有記錄時退出循環
dbms_output.put_line(v_event_id || ', ' || v_isagain || ', ' || v_rate);
end loop;
close cursorVar; -- 關閉游標
end;
3.異常處理
EXCEPTION
WHEN OTHERS THEN
vs_msg := 'ERROR IN xxxxxxxxxxx_p('||is_ym||'):'||SUBSTR(SQLERRM,1,500);
ROLLBACK;
--把當前錯誤記錄進日志表。
INSERT INTO LOG_INFO(proc_name,error_info,op_date)
VALUES('xxxxxxxxxxx_p',vs_msg,SYSDATE);
COMMIT;
RETURN;
4.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;
5.用for in 來使用游標cursor
procedure copy(a_id int) is
cursor t_cursor is --定義名為t_cursor的游標
select * from table f where f.id = a_id;
v_row table%rowtype;
begin
for v_row in t_cursor loop
--循環之前定義的t_cursor游標將其中多行查詢結果一行行遍歷。
-- 處理數據
end loop;
end copy
關于oracle存儲過程的若干問題備忘。
1.存儲過程中as分隔存儲過程名(+參數名)和變量名。
因而數據庫表別名定義時不可加as
2.在select字段時后面必須緊跟into +變量名,否者報錯Compilation;除非使用游標select整個字段列。
3.select ~into在使用時須確保select字段存在,否者報錯no datafound。因此可提前使用select count(*) from xxx查看存在與否。
4.存儲過程中的別名不可與字段名重復,否則雖可編譯但運行報錯。
5.在存儲過程中定義的變量ss接收了一個結果為null的查詢。那么即便之前ss定義了一個默認值,ss的值也依舊會被覆蓋為null。
createtable table1(
name varchar2(10) primary key not null,
age number(10) not null,
sex varchar2(2) not null,--外鍵
);
--存儲過程中有如下語句:
ss number(10) := 0;--定義ss默認值為數字0.
...
select sum(age) into ss from table1 where name = 'tiny';
--此時表table1中不存在name為tiny的值;則此時的ss 依舊為null;
解決方式為之后判斷ss的值若為null再次賦值即可。
if ss is null then
ss := 0;
end if;
6.Hibernate調用oracle存儲過程:
this.pnumberManager.getHibernateTemplate().execute(
new HibernateCallback() {
public ObjectdoInHibernate(Session session)
throws HibernateException,SQLException {
CallableStatementcs = session
.connection()
.prepareCall("{callmodifyapppnumber_remain(?)}");
cs.setString(1,foundationid);
cs.execute();
return null;
}
});
7.1oracle 存儲過程中使用Sequence:
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;
7.2創建一個存儲過程用來記錄序列(insert Record With Sequence)
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;
--此處test表的定義,和前面的示例不同。其中,UserID是PK。
7.3存儲過程中包的定義:
為了讓存儲過程返回結果集,必須定義一個游標變量作為輸出參數。這和SqlServer中有著很大的不同!并且還要用到Oracle中“包”(Package)的概念,似乎有點繁瑣,但熟悉后也會覺得很方便。
關于“包”的概念,有很多內容可以參考,在此就不贅述了。首先,我創建了一個名為TestPackage的包,包頭是這么定義的:
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()方法前進到下一個游標。
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;
包體如下:
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
8.1項目級存儲過程實例:
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;
/
8.2帶游標的存儲過程詳例:
--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;
9.1存儲過程function的使用詳例:
--包定義
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;
--包主題
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;