Oracle存儲過程語法代碼示例詳解
簡介
存儲過程是一系列SQL語句的集合,可以封裝復雜的邏輯,實現(xiàn)特定的功能,可以提高執(zhí)行速度和代碼的復用性,預先編譯后存儲在數(shù)據(jù)庫中,可以通過指定存儲過程的名稱對其進行調用。
本文主要講解Oracle存儲過程語法,包括:總體結構、存儲過程聲明、參數(shù)定義、變量聲明、游標聲明、行數(shù)據(jù)類型聲明、變量賦值、條件判斷、WHILE循環(huán)、FOR循環(huán)、游標使用、異常捕捉、異常處理、存儲過程調用、存儲過程代碼示例、調用代碼示例、調用結果展示。
總體結構
一個完整的存儲過程結構主要包括:過程聲明部分、過程執(zhí)行部分、異常處理部分,如下所示。
CREATE OR REPLACE PROCEDURE 存儲過程名稱(參數(shù)定義部分)
AS或IS
變量聲明部分
BEGIN
過程執(zhí)行部分
EXCEPTION
異常處理部分
END;
樣例準備
先準備樣例表TESTTABLE01,數(shù)據(jù)如下圖,后續(xù)所有代碼示例查詢的數(shù)據(jù)都來自這個表。

過程聲明部分
聲明格式
CREATE OR REPLACE PROCEDURE 存儲過程名稱(參數(shù)定義部分)
AS或IS
其中,【OR REPLACE】表示如果已存在同名的存儲過程,則直接替換,即將其覆蓋掉,這部分也可以省略,省略后,執(zhí)行編譯時,如果發(fā)現(xiàn)同名的存儲過程,則會報錯提示ORA-00955,如下圖。AS或IS兩種寫法效果相同,任選其一。

參數(shù)定義
格式:【參數(shù)名 輸入輸出類型 數(shù)據(jù)類型】,可定義輸入或輸出的參數(shù),可以不帶參數(shù),也可以定義一個或多個參數(shù),多個參數(shù)用英文逗號隔開,如下所示。
過程聲明和參數(shù)定義示例
CREATE OR REPLACE PROCEDURE TESTSP01( para01 in VARCHAR2, para02 in INT, para03 out VARCHAR2 ) AS
para01、para02、para03為自定義的參數(shù)名;in或out表示輸入或輸出參數(shù),輸入?yún)?shù)是在調用存儲過程時傳入的,輸出參數(shù)是在存儲過程內部賦值的,可以輸出;VARCHAR2、INT表示參數(shù)的數(shù)據(jù)類型。
說明:【in out】表示該參數(shù)既是輸入?yún)?shù)也是輸出參數(shù)。
變量聲明
格式:【變量名 數(shù)據(jù)類型】,變量聲明是在BEGIN前面。
可以定義存儲過程中需要用到的變量,每個變量用英文分號結尾,如下所示。
var01 VARCHAR2(10); var02 VARCHAR2(20); var03 INT; var04 NUMBER(5); var05 VARCHAR2(50);
游標聲明
格式:【CURSOR 游標名稱 IS 查詢語句】,游標是內存中用于存儲和檢索查詢結果集的一種數(shù)據(jù)結構,可以用來遍歷的有多條數(shù)據(jù)的查詢結果。
示例:
CURSOR cursor01 IS SELECT COL01,COL02,COL03 FROM TESTTABLE01 WHERE COL02 IS NOT NULL;
行數(shù)據(jù)類型
聲明游標之后,需要再聲明一個行數(shù)據(jù)類型,用以存儲游標中的某一行數(shù)據(jù),也可以存儲表中的一行數(shù)據(jù)。
格式:
行變量名稱 游標名稱%ROWTYPE;
行變量名稱 表名稱%ROWTYPE;
示例:
row01 cursor01%ROWTYPE; row02 TESTTABLE01%ROWTYPE;
過程執(zhí)行部分
變量賦值
格式:【變量名:=變量值】,如下所示,可以將常量、變量等賦值給變量。
var01:='hello'; var02:=var01; var03:=8; var04:=1.8; var05:=var02||' world';
也可以在變量聲明的時候直接賦值,如下所示。
var03 INT:=8; var04 NUMBER(5,2):=1.8; var05 VARCHAR2(50):='hello world';
還可以把SQL語句的查詢結果賦值給變量,格式:【select 字段名或表達式 into 變量名 from ...】,如下所示。
select count(1) into var03 from TESTTABLE01; select col02 into var01 from TESTTABLE01 where col01='id01'; select replace(col02,'value','hello')||' world' into var05 from TESTTABLE01 where col01='id01';
條件判斷
格式如下:若條件判斷表達式01為真,則執(zhí)行代碼塊01,當不滿足表達式01時,繼續(xù)判斷,若條件判斷表達式02為真,則執(zhí)行代碼塊02,若前面的條件都不滿足,則執(zhí)行代碼塊03。其中ELSIF(注意寫法不是ELSEIF)和ELSE部分都可以省略。
IF 條件判斷表達式01 THEN
代碼塊01
ELSIF 條件判斷表達式02 THEN
代碼塊02
ELSE
代碼塊03
END IF;
示例:
IF var01 like 'value%' THEN
var02:='ret01';
ELSIF var03>1 THEN
var02:='ret02';
ELSE
var02:='ret03';
END IF;WHILE循環(huán)
第一種寫法如下:如果條件表達式為真,再執(zhí)行里面的代碼塊,否則不執(zhí)行。
WHILE 條件表達式 LOOP
代碼塊
END LOOP ;
第二種寫法如下:先執(zhí)行一次LOOP中的代碼塊,再判斷條件表達式,如果為真,則退出循環(huán),否則,繼續(xù)執(zhí)行循環(huán),這種寫法與第一種寫法的區(qū)別在于,不論條件表達式結果如何,LOOP中的代碼塊會至少執(zhí)行一次。
LOOP
代碼塊
EXIT WHEN 條件表達式
END LOOP;
FOR循環(huán)
格式:每一次執(zhí)行循環(huán)時,會將索引自增一次,從索引范圍的最小值開始自增,伴隨著每一次循環(huán),直到索引達到索引范圍的最大值,就退出循環(huán)。
FOR 索引 IN 索引范圍 LOOP
代碼塊;
END LOOP;
示例:
-- for循環(huán)依次輸出1到8
FOR i IN 1..8 LOOP
var08:=var08||i;
END LOOP;
dbms_output.put_line('for循環(huán)輸出1到8:'||var08);游標使用
打開游標:【OPEN 游標名稱】;
獲取游標數(shù)據(jù)放入行變量:【FETCH 游標名稱 INTO 行變量名稱】,其中,F(xiàn)ETCH在獲取當前行數(shù)據(jù)的同時,還會把游標指針推進到下一條紀錄,一般放在循環(huán)結構中遍歷獲取每一條數(shù)據(jù)。
游標的屬性:
【游標名稱%ISOPEN】:表示游標是否打開,正常情況返回布爾型;
【游標名稱%FOUND】:表示游標是否獲取到數(shù)據(jù),正常情況返回布爾型;
【游標名稱%NOTFOUND】:表示游標是否沒有獲取到數(shù)據(jù),正常情況返回布爾型;
【游標名稱%ROWCOUNT】:返回游標已經(jīng)遍歷獲取的記錄數(shù),不是總數(shù)量,返回INT型。
示例:
var061:=cursor01%ISOPEN; -- 游標cursor01是否打開 var062:=cursor01%FOUND; -- 游標cursor01是否獲取到數(shù)據(jù) var063:=cursor01%NOTFOUND; -- 游標cursor01是否沒有獲取到數(shù)據(jù) var064:=cursor01%ROWCOUNT; -- 返回游標cursor01已經(jīng)遍歷獲取的記錄數(shù),不是總數(shù)量
關閉游標:【CLOSE 游標名稱】。
示例1,使用while...loop循環(huán)方式讀取游標數(shù)據(jù):
-- while...loop循環(huán)方式
dbms_output.put_line('while...loop循環(huán)方式:');
OPEN cursor01; -- 打開游標cursor01
var061:=cursor01%ISOPEN; -- 游標是否打開
var062:=cursor01%FOUND; -- 游標是否獲取到數(shù)據(jù)
var063:=cursor01%NOTFOUND; -- 游標是否沒有獲取到數(shù)據(jù)
FETCH cursor01 INTO row01; -- 從游標cursor01獲取行數(shù)據(jù)賦給行變量row01,并將游標推進到下一行。
WHILE cursor01%FOUND LOOP --如果cursor01%FOUND結果為真,則執(zhí)行while循環(huán)
BEGIN
var_col01 := row01.COL01; -- 獲取行變量中的具體字段值賦給左邊的變量
var_col02 := row01.COL02; -- 獲取行變量中的具體字段值賦給左邊的變量
dbms_output.put_line('獲取記錄數(shù):'||cursor01%ROWCOUNT); -- 輸出內容
dbms_output.put_line('當前行數(shù)據(jù):'||var_col01||','||var_col02); -- 輸出內容
FETCH cursor01 INTO row01; -- 從游標cursor01獲取行數(shù)據(jù)賦給行變量row01,并將游標推進到下一行。
END;
END LOOP;
CLOSE cursor01; -- 關閉游標cursor01示例2,使用loop... exit when...循環(huán)方式讀取游標數(shù)據(jù):
-- loop... exit when...循環(huán)方式
dbms_output.put_line('loop... exit when...循環(huán)方式:');
OPEN cursor01; -- 打開游標cursor01
LOOP
FETCH cursor01 INTO row01; -- 從游標cursor01獲取行數(shù)據(jù)賦給行變量row01,并將游標推進到下一行。
EXIT WHEN cursor01%NOTFOUND; -- 如果cursor01%NOTFOUND結果為真,則退出循環(huán)。
var_col01 := row01.COL01; -- 獲取行變量中的具體字段值賦給左邊的變量
var_col02 := row01.COL02; -- 獲取行變量中的具體字段值賦給左邊的變量
dbms_output.put_line('獲取記錄數(shù):'||cursor01%ROWCOUNT); -- 輸出內容
dbms_output.put_line('當前行數(shù)據(jù):'||var_col01||','||var_col02); -- 輸出內容
END LOOP ;
CLOSE cursor01; -- 關閉游標cursor01示例3,使用for循環(huán)方式讀取游標數(shù)據(jù):
-- for循環(huán)讀取游標數(shù)據(jù)
dbms_output.put_line('for循環(huán)讀取游標數(shù)據(jù):');
FOR row01 IN cursor01 LOOP -- 遍歷游標cursor01獲取數(shù)據(jù)賦給行變量row01
var_col01 := row01.COL01; -- 獲取行變量中的具體字段值賦給左邊的變量
var_col02 := row01.COL02; -- 獲取行變量中的具體字段值賦給左邊的變量
dbms_output.put_line('獲取記錄數(shù):'||cursor01%ROWCOUNT); -- 輸出內容
dbms_output.put_line('當前行數(shù)據(jù):'||var_col01||','||var_col02); -- 輸出內容
END LOOP;異常處理部分
異常捕捉
格式:EXCEPTION可以捕捉到存儲過程執(zhí)行中遇到的異常,WHEN后面是具體的異常名稱,捕捉到具體異常后,就會執(zhí)行對應WHEN下面的異常處理代碼塊,如果捕捉到的異常和前面任何一個WHEN后面的異常名稱都不匹配,則直接執(zhí)行【W(wǎng)HEN OTHERS THEN】下面的異常處理代碼。
EXCEPTION
WHEN 異常01 THEN
異常處理代碼塊01
WHEN 異常02 THEN異常處理代碼塊02
......
WHEN OTHERS THEN
異常處理代碼塊n
異常處理部分也可以只有OTHERS部分,格式如下,捕捉到任何異常都會跳轉到OTHERS對應的異常處理代碼塊。
EXCEPTION
WHEN OTHERS THEN
異常處理代碼塊
異常處理
SQLCODE:獲取錯誤代碼,
SQLERRM:獲取具體的錯誤信息,
ROLLBACK:回滾事務。
異常處理示例:
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('未查詢到數(shù)據(jù)!');
WHEN CURSOR_ALREADY_OPEN THEN
dbms_output.put_line('游標已經(jīng)打開!');
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE); -- 輸出錯誤代碼
dbms_output.put_line(SQLERRM); -- 輸出錯誤信息調用存儲過程 調用命令格式
如果存儲過程不帶參數(shù),調用格式如下。
call 存儲過程名稱();
如果存儲過程只帶輸入?yún)?shù),參數(shù)值用英文逗號隔開,傳入的值要和存儲過程定義的參數(shù)的順序和類型保持一致,調用格式如下。
call 存儲過程名稱(參數(shù)值1,參數(shù)值2,...);
如果存儲過程帶輸出參數(shù),比如某個存儲過程有三個參數(shù),前兩個為輸入?yún)?shù),第三個為輸出參數(shù),調用格式如下,需要先定義一個變量用來接收輸出參數(shù)值,數(shù)據(jù)類型要和輸出參數(shù)相同。
BEGIN
DECLARE
變量名01 數(shù)據(jù)類型;
BEGIN
存儲過程名稱(傳入值01,傳入值02,變量名01);
END;
END;
完整存儲過程示例
-- 存儲過程聲明,可以帶參數(shù),也可以不帶參數(shù)
CREATE OR REPLACE PROCEDURE TESTSP01(
para01 in VARCHAR2,
para02 in INT,
para03 out VARCHAR2
)
AS
-- 變量定義,可以在變量定義時賦值。
var01 VARCHAR2(10);
var02 VARCHAR2(20);
var03 INT:=0;
var04 NUMBER(5,2):=8.88;
var05 VARCHAR2(50):='initvalue';
var06 INT;
var061 BOOLEAN;
var062 BOOLEAN;
var063 BOOLEAN;
var07 VARCHAR2(30);
var08 VARCHAR2(20):='';
var_col01 VARCHAR2(20);
var_col02 VARCHAR2(20);
-- 游標聲明
CURSOR cursor01 IS
SELECT COL01,COL02,COL03
FROM TESTTABLE01
WHERE COL02 IS NOT NULL;
-- 行變量聲明
row01 cursor01%ROWTYPE;
row02 TESTTABLE01%ROWTYPE;
BEGIN -- 過程執(zhí)行部分
-- 變量賦值,可以將常量或變量賦值給變量
dbms_output.put_line('變量賦值示例:');
var01:='hello';
var02:=var01;
var03:=8;
var04:=1.8;
dbms_output.put_line('var01:'||var01||','||'var02:'||var02||','||'var03:'||var03||','||'var04:'||var04);
-- 通過sql查詢給變量賦值
select col02 into var05 from TESTTABLE01 where col01='id01';
select count(1) into var06 from TESTTABLE01;
select replace(col02,'value','hello')||' world' into var07 from TESTTABLE01 where col01='id01';
dbms_output.put_line('var05:'||var05||','||'var06:'||var06||','||'var07:'||var07);
-- IF判斷示例
dbms_output.put_line('IF判斷示例:');
IF para01 like 'value%' THEN
dbms_output.put_line('IF判斷滿足第一個分支');
ELSIF para02>1 THEN
dbms_output.put_line('IF判斷滿足第二個分支');
ELSE
dbms_output.put_line('IF判斷滿足第三個分支');
END IF;
-- while...loop循環(huán)方式讀取游標數(shù)據(jù)
dbms_output.put_line('while...loop循環(huán)方式讀取游標數(shù)據(jù):');
OPEN cursor01; -- 打開游標cursor01
var061:=cursor01%ISOPEN; -- 游標cursor01是否打開
var062:=cursor01%FOUND; -- 游標cursor01是否獲取到數(shù)據(jù)
var063:=cursor01%NOTFOUND; -- 游標cursor01是否沒有獲取到數(shù)據(jù)
FETCH cursor01 INTO row01; -- 從游標cursor01獲取行數(shù)據(jù)賦給行變量row01,并將游標推進到下一行。
WHILE cursor01%FOUND LOOP --如果cursor01%FOUND結果為真,則執(zhí)行while循環(huán)
BEGIN
var_col01 := row01.COL01; -- 獲取行變量中的具體字段值賦給左邊的變量
var_col02 := row01.COL02; -- 獲取行變量中的具體字段值賦給左邊的變量
dbms_output.put_line('獲取記錄數(shù):'||cursor01%ROWCOUNT); -- 輸出內容
dbms_output.put_line('當前行數(shù)據(jù):'||var_col01||','||var_col02); -- 輸出內容
FETCH cursor01 INTO row01; -- 從游標cursor01獲取行數(shù)據(jù)賦給行變量row01,并將游標推進到下一行。
END;
END LOOP;
CLOSE cursor01; -- 關閉游標cursor01
-- loop... exit when...循環(huán)方式讀取游標數(shù)據(jù)
dbms_output.put_line('loop... exit when...循環(huán)方式讀取游標數(shù)據(jù):');
OPEN cursor01; -- 打開游標cursor01
LOOP
FETCH cursor01 INTO row01; -- 從游標cursor01獲取行數(shù)據(jù)賦給行變量row01,并將游標推進到下一行。
EXIT WHEN cursor01%NOTFOUND; -- 如果cursor01%NOTFOUND結果為真,則退出循環(huán)。
var_col01 := row01.COL01; -- 獲取行變量中的具體字段值賦給左邊的變量
var_col02 := row01.COL02; -- 獲取行變量中的具體字段值賦給左邊的變量
dbms_output.put_line('獲取記錄數(shù):'||cursor01%ROWCOUNT); -- 輸出內容
dbms_output.put_line('當前行數(shù)據(jù):'||var_col01||','||var_col02); -- 輸出內容
END LOOP ;
CLOSE cursor01; -- 關閉游標cursor01
-- for循環(huán)依次輸出1到8
FOR i IN 1..8 LOOP
var08:=var08||i;
END LOOP;
dbms_output.put_line('for循環(huán)輸出1到8:'||var08);
-- for循環(huán)讀取游標數(shù)據(jù)
dbms_output.put_line('for循環(huán)讀取游標數(shù)據(jù):');
FOR row01 IN cursor01 LOOP -- 遍歷游標cursor01獲取數(shù)據(jù)賦給行變量row01
var_col01 := row01.COL01; -- 獲取行變量中的具體字段值賦給左邊的變量
var_col02 := row01.COL02; -- 獲取行變量中的具體字段值賦給左邊的變量
dbms_output.put_line('獲取記錄數(shù):'||cursor01%ROWCOUNT); -- 輸出內容
dbms_output.put_line('當前行數(shù)據(jù):'||var_col01||','||var_col02); -- 輸出內容
END LOOP;
--給輸出參數(shù)賦值
para03:='存儲過程執(zhí)行成功!';
EXCEPTION -- 異常處理部分
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('未查詢到數(shù)據(jù)!');
WHEN CURSOR_ALREADY_OPEN THEN
dbms_output.put_line('游標已經(jīng)打開!');
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE); -- 輸出錯誤代碼
dbms_output.put_line(SQLERRM); -- 輸出錯誤信息
END;調用存儲過程示例
BEGIN
DECLARE
-- 定義變量接收輸出參數(shù)值,數(shù)據(jù)類型要和輸出參數(shù)相同
outpara VARCHAR2(50);
BEGIN
-- 調用存儲過程,給輸入?yún)?shù)賦值,將事先定義的變量傳給輸出參數(shù)。
TESTSP01('value_in',8,outpara);
-- 打印輸出參數(shù)
dbms_output.put_line('輸出參數(shù)值:'||outpara);
END;
END;調用輸出結果展示

到此這篇關于Oracle存儲過程語法詳解的文章就介紹到這了,更多相關Oracle存儲過程語法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Oracle通過LogMiner實現(xiàn)數(shù)據(jù)同步遷移
這篇文章主要介紹了Oracle通過LogMiner實現(xiàn)數(shù)據(jù)同步遷移的方法,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下2020-07-07
Oracle數(shù)據(jù)庫自動備份腳本分享(超實用)
這篇文章主要給大家分享介紹了關于Oracle數(shù)據(jù)庫自動備份腳本的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-12-12
Windows系統(tǒng)安裝Oracle 11g 數(shù)據(jù)庫圖文教程
這篇文章主要介紹了Windows系統(tǒng)安裝Oracle 11g 數(shù)據(jù)庫圖文教程,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-10-10
Oracle數(shù)據(jù)庫中RETURNING子句的使用
RETURNING子句允許您檢索插入、刪除或更新所修改的列的值,本文主要介紹了Oracle數(shù)據(jù)庫中RETURNING子句的使用,感興趣的可以了解一下2024-08-08
oracle刪除主鍵查看主鍵約束及創(chuàng)建聯(lián)合主鍵
本節(jié)文章主要介紹了oracle刪除主鍵查看主鍵約束及創(chuàng)建聯(lián)合主鍵,示例代碼如下,需要的朋友可以參考下2014-07-07

