創建/更新存儲過程 基礎基礎用法 創建/修改無參存儲過程 CREATE OR REPLACE PROCEDURE procedure_name [IS|AS] --聲明全局變數(可選) BEGIN --存儲過程的執行體 END; --也可以寫成 END procedure_name; 創建/修改攜參 ...
創建/更新存儲過程
基礎基礎用法
創建/修改無參存儲過程
CREATE OR REPLACE PROCEDURE procedure_name [IS|AS]
--聲明全局變數(可選)
BEGIN
--存儲過程的執行體
END; --也可以寫成 END procedure_name;
創建/修改攜參數存儲過程
CREATE OR REPLACE PROCEDURE procedure_name(var_name1 IN type, var_name2 IN type,...,var_nameN OUT type) [IS|AS]
--聲明全局變數(可選)
BEGIN
--存儲過程的執行體
END; --也可以寫成 END procedure_name;
說明:IN 表示輸入參數,OUT表示輸出參數,比如存儲返回值的變數,IN OUT 表示輸入輸出參數(註:都不區分大小寫)
註意:
- 存儲過程參數數據類型不能指定長度
- OUT、IN OUT 模式參數的調用,必須通過變數實現
調用存儲過程
--調用帶參數存儲過程
CALL procedure_name([參數列表]);
--或者
BEGIN procedure_name(參數列表); END; --註意 分號不能少,特別是END後面的分號
--或者
SQL> EXEC procedure_name(參數列表); --在命令行視窗執行,比如SQLPlus執行視窗
--調用不帶參數存儲過程
CALL procedure_name();
--或者
BEGIN procedure_name; END; --註意 分號不能少,特別是END後面的分號
--或者
BEGIN procedure_name(); END; --註意 分號不能少,特別是END後面的分號
--或者
SQL> EXEC procedure_name;
簡單的示例
創建攜帶參數存儲過程
CREATE OR REPLACE PROCEDURE SP_TEST_PROC(workDate IN Date) is
BEGIN
dbms_output.put_line('The input date is:'||to_date(workDate,'yyyy-mm-dd'));
END;
CALL SP_TEST_PROC(sysdate); --輸出:The input date is:22-AUG-24
--創建攜帶返回值存儲過程
CREATE OR REPLACE PROCEDURE SP_SUM_PROC(number1 IN NUMBER, number2 IN NUMBER, result OUT NUMBER) is
BEGIN
result := number1 + number2;
END;
-- sql視窗中調用
DECLARE res NUMBER(6);
BEGIN
SP_SUM_PROC(1, 3, res);
dbms_output.put_line(res); --輸出:4
END;
-- 命令行視窗中調用
SQL> VARIABLE res NUMBER;
SQL> EXEC SP_SUM_PROC(1, 3, :res);
PL/SQL procedure successfully completed
res
---------
4
--創建帶輸入輸出參數的存儲過程
CREATE OR REPLACE PROCEDURE SP_SUM_PROC(number1 IN NUMBER, number2 IN OUT NUMBER) is
BEGIN
number2 := number1 + number2;
END;
-- 調用
DECLARE num NUMBER(6) :=3; --註意,不能在存儲過程中聲明變數時這樣賦值
BEGIN
dbms_output.put_line('調用前num變數值:' || num); --輸出:調用前num變數值:3
SP_SUM_PROC(1, num);
dbms_output.put_line('調用後num變數值:' || num); --輸出:調用後num變數值:4
END;
DECLARE基礎用法說明
可以在BEGIN
關鍵字之前,使用DECLARE
定義、聲明局部變數,聲明基礎用法如下:
DECLARE 變數名[,變數名2...] 數據類型(含長度、精度) [DEFAULT value]; --沒有使用DEFAULT子句時,預設值為NULL
示例:
DECLARE num INT DEFAULT 10; --聲明變數 num,數據類型為INT型,預設值為10
DECLARE usrname VARCHAR2(15) DEFAULT 'tester'; --聲明變數 username,預設值為tester
DECLARE age, num int; -- 定義多個變數
DECLARE length, width NUMBER(18,2) DEFAULT 10; -- 聲明變數 length, width,預設值都為10
BEGIN
-- do something
END;
創建無參數存儲過程
CREATE OR REPLACE PROCEDURE SP_TEST_PROC is
BEGIN
dbms_output.put_line('hello, tester');
END;
--調用
CALL SP_TEST_PROC(); --輸出:hello, tester
--或者
BEGIN
SP_TEST_PROC;
END;
聲明全局變數
方式一:直接聲明數據類型
格式:變數名 數據類型(大小及精度)
示例:
v_username VARCHAR2(15);
v_num NUMBER(9,2);
方式二:使用%TYPE
聲明
格式:變數名 表名.欄位名%TYPE
含義:該變數的數據類型與指定表的指定欄位的數據類型一致
示例:
r_carrierID CARRIERS.carrier_id%type;
方式三:使用%ROWTYPE
聲明
格式:變數名 表名%ROWTYPE
含義:該變數的數據類型與指定表的指定行記錄(所有欄位)的數據類型一致
示例:
V_row_user USERS%ROWTYPE; --V_row_user存放整行數據
註:不管使用哪種聲明方式,變數名都不區分大小寫,以字母開頭;此外,變數的聲明必須在BEGIN
關鍵字之前進行。
變數賦值
方式一:使用":="直接賦值
註意,這種方式不適合使用%ROWTYPE
聲明的變數
示例:
v_username := 'shouke';
我們可以在聲明變數的同時對變數進行賦值。
v_username VARCHAR2(15) := 'shouke'
方式二:select 表欄位 into 變數 from 表
1:查詢指定表的某些指定欄位
不適合使用%ROWTYPE
聲明的變數
SELECT field1,field2,...,field3 INTO varName1,varName2,...,varNameN FROM tableName;
2:查詢指定表的所有欄位
SELECT * INTO v_row_varName FROM tableName; --其中v_row_varName為使用%ROWTYPE聲明的變數
註意:使用這種方式給使用%ROWTYPE
聲明的變數賦值時,查詢結果只能返回一條記錄,且查詢結果必須包含該表的所有欄位。
變數聲明與賦值示例
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
v_username VARCHAR2(15);
v_companyCode NUMBER(9,2);
v_erpOrderNo EFFECTIVE_OMS_MSG_FOR_TEST.erp_Orderno%TYPE;
v_record EFFECTIVE_OMS_MSG_FOR_TEST%ROWTYPE;
BEGIN
v_username := 'shouke';
SELECT request_msg_id INTO v_companyCode FROM EFFECTIVE_MSG_FOR_TEST WHERE rownum <2;
SELECT erp_orderno INTO v_erpOrderNo FROM EFFECTIVE_MSG_FOR_TEST WHERE rownum <2;
SELECT * INTO v_record FROM EFFECTIVE_MSG_FOR_TEST WHERE rownum <2;
dbms_output.put_line('v_username: ' || v_username);
dbms_output.put_line('v_companyCode: ' || v_companyCode);
dbms_output.put_line('v_erpOrderNo: ' || v_erpOrderNo);
dbms_output.put_line('v_record.company_code: ' || v_record.company_code);
END;
call SP_TEST_PROC();
註意:
- 採用變數名.表欄位名的方式來引用通過
%ROWTYPE
聲明的變數 - 不能直接使用變數名作為查詢列,錯誤用法形如
SELECT v_erpOrderNo FROM EFFECTIVE_MSG_FOR_TEST;
一個應用實例
--創建序列
CREATE SEQUENCE check_orders_seq
increment By 1
start With 1
Maxvalue 2000
Minvalue 1
cycle
Nocache;
--創建存儲過程
CREATE OR REPLACE PROCEDURE "SP_GET_CHECK_ORDERS_FOR_TEST" (IN_serverID IN VARCHAR2, IN_rowLimit IN INT, OUT_returnCode OUT VARCHAR2)
IS
sqlStr VARCHAR2(5000);
BEGIN
OUT_returnCode := '000';
--將揀貨完成未覆核,且未在臨時表check_orders_for_test的訂單拉入臨時表
sqlStr := 'insert into check_orders_for_test(warehouseID, orderNo, rangeNo, checkFlag, serverID) select h.warehouseID, h.orderNo, check_orders_seq.nextval rangeNo, ''N'' checkFlag,'''||IN_serverID||''' serverID
from doc_order_header h
where h.sostatus = ''60''
and exists (select 1 from act_allocation_details a
where a.orderNo = h.orderNo
and a.packflag = ''N'')
and not exists (select 1 from check_orders_for_test m
where m.orderno = h.orderno)
and rownum <= '||IN_rowLimit;
execute immediate sqlStr;
commit;
Return;
EXCEPTION
WHEN OTHERS THEN
OUT_returnCode := 'SP_GET_CHECK_ORDERS_FOR_TEST' || SQLerrm;
dbms_output.put_line(OUT_returnCode);
ROLLBACK;
END;
說明:兩個''
表示一個'
執行體之邏輯判斷語句
IF語句
基礎用法
IF 條件表達式 THEN
-- do something
END IF;
IF 條件表達式 THEN
-- do something
ELSE
-- do something
END IF;
IF 條件表達式 THEN
-- do something
ELSIF 條件表達式 THEN
-- do something
... --表省略,支持更多的ELSIF
ELSE --子句可選
-- do something
END IF;
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC(num IN NUMBER) IS
BEGIN
--如果num為1,則輸出true
IF num=1 THEN
BEGIN
dbms_output.put_line('true');
END;
END IF;
END;
CALL SP_TEST_PROC(1);
CREATE OR REPLACE PROCEDURE SP_TEST_PROC(num IN NUMBER) IS
BEGIN
IF NUM=1 THEN --如果num為1,則輸出 true
dbms_output.put_line('true');
ELSE --否則輸出 false
dbms_output.put_line('false');
END IF;
END;
CREATE OR REPLACE PROCEDURE SP_TEST_PROC(num IN NUMBER) IS
BEGIN
IF NUM=1 THEN --如果num為1,則輸出 true
dbms_output.put_line('true');
ELSIF NUM=0 THEN --否則,如果num為2,則輸出 false
dbms_output.put_line('false');
ELSE --否則輸出 invalid num
dbms_output.put_line('invalid num');
END IF;
END;
CASE WHEN語句
基礎用法
CASE
WHEN num=1 THEN
--do something
WHEN num=2 THEN
--do something
... --表省略,支持更多的WHEN
ELSE
--do something
END CASE;
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC(num IN NUMBER) IS
BEGIN
CASE
WHEN num=1 THEN --如果num為1,則輸出 true
dbms_output.put_line('true');
WHEN num=2 THEN --如果num為1,則輸出 false
dbms_output.put_line('false');
ELSE --否則輸出 invalid num
dbms_output.put_line('invalid num');
END CASE;
END;
執行體之迴圈遍歷語句
FOR迴圈
基礎用法
FOR var IN range LOOP
--do something
END LOOP;
--遍歷查詢結果集
FOR row IN (查詢語句) LOOP
--do something
END LOOP;
--迴圈遍曆數組
--迴圈遍歷游標(使用示例參見下文 執行體之游標)
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
BEGIN
-- FOR i IN REVERSE 0..5 LOOP --REVERSE 採用逆序,從大到小,i取值從5到0
FOR i IN 0..5 LOOP -- i取值從0到5
dbms_output.put_line('運行第' || i || '次');
END LOOP;
END;
CALL SP_TEST_PROC();
運行輸出:
運行第0次
運行第1次
運行第2次
運行第3次
運行第4次
運行第5次
遍歷查詢結果集
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
BEGIN
FOR cur_row IN (SELECT request_msg_id, erp_orderno FROM effective_oms_msg_for_test WHERE ROWNUM<5)
LOOP
dbms_output.put_line('msg_id: ' || cur_row.request_msg_id || ' orderno: ' || cur_row.erp_orderno);
END LOOP;
END;
CALL SP_TEST_PROC();
WHILE迴圈
基礎用法
WHILE 條件語句 LOOP
-- do something
END LOOP;
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
i INT :=1 ;
BEGIN
WHILE i < 3 LOOP
dbms_output.put_line('運行第' || i || '次');
i := i + 1;
END LOOP;
END;
CALL SP_TEST_PROC();
調用輸出
運行第1次
運行第2次
LOOP迴圈
基礎用法
LOOP
--do something
IF 退出迴圈條件 THEN
--do something
EXIT;
END IF;
--do something
END LOOP;
LOOP
--do something
EXIT WHEN 退出迴圈條件;
--do something
END LOOP;
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
i INT :=1;
BEGIN
LOOP
IF i=3 THEN --如果i=3,則退出
EXIT;
END IF;
dbms_output.put_line('運行第' || i || '次');
i := i + 1;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
i INT :=1;
BEGIN
LOOP
EXIT WHEN i = 3;
dbms_output.put_line('運行第' || i || '次');
i := i + 1;
END LOOP;
END;
調用結果,同上述WHILE
迴圈示例
執行體之GOTO跳轉語句
基礎用法
<<gotoLabel>>
-- do something
GOTO gotoLabel;
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
i int := 1;
BEGIN
<<loop_lable>>
dbms_output.put_line('運行第' || i || '次');
i := i + 1;
IF i < 3 THEN
GOTO loop_lable;
END IF;
END;
調用結果,同上述WHILE
迴圈示例
說明:如上,我們也可以利用GOTO語句來實現迴圈
執行體之游標
基礎用法
CURSOR型游標
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
CURSOR cursor_name IS 查詢語句; -- 定義CURSOR類型游標(不能用於參數傳遞)
BEGIN
FOR varName IN cursor_name LOOP
--do something --引用變數 varName.field
END LOOP;
END;
註意:通過以上方式,採用FOR
迴圈遍歷游標,會自動關閉游標,不需要在END LOOP;
後添加關閉游標的代碼CLOSE cursor_name;
,會報錯
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
CURSOR cursor_for_msgs IS SELECT request_msg_id, erp_orderno FROM effective_msg_for_test WHERE ROWNUM<5;
BEGIN
FOR msg IN cursor_for_msgs LOOP
dbms_output.put_line('msg_id: ' || msg.request_msg_id || ' orderno: ' || msg.erp_orderno);
END LOOP;
END;
SYS_REFCURSOR型游標
SYS_REFCURSOR型游標,該游標是Oracle以預先定義的游標,可作出參數進行傳遞
基礎用法
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
v_cursor_name SYS_REFCURSOR ;
--變數定義
BEGIN
OPEN v_cursor_name FOR 查詢語句;
LOOP
FETCH v_cursor_name INTO 變數1, 變數2, ..., 變數N; --變數個數和查詢結果記錄包含的欄位數量保持一致
EXIT WHEN v_cursor_name%NOTFOUND;
END LOOP;
CLOSE v_cursor_name;
END;
說明: SYS_REFCURSOR中可使用三個狀態屬性:
%NOTFOUND
表示未找到記錄信息%FOUND
表示找到記錄信息%ROWCOUNT
表示當前游標所指向的行位置%ISOPEN
如果游標已經打開,則返回TRUE
,否則返回FALSE
註意:
-
SYS_REFCURSOR游標只能通過
OPEN
方法來打開和賦值 -
SYS_REFCURSOR游標只能通過
FETCH INTO
方法來遍歷取值
示例
CREATE OR REPLACE PROCEDURE SP_TEST_PROC IS
v_cursor_for_msgs SYS_REFCURSOR ;
v_request_msg_id VARCHAR2(20);
v_erp_orderno VARCHAR2(50);
BEGIN
OPEN v_cursor_for_msgs FOR SELECT request_msg_id, erp_orderno FROM effective_msg_for_test WHERE ROWNUM<5;
LOOP
FETCH v_cursor_for_msgs INTO v_request_msg_id, v_erp_orderno;
EXIT WHEN v_cursor_for_msgs%NOTFOUND;
dbms_output.put_line('msg_id: ' || v_request_msg_id || ' orderno: ' || v_erp_orderno);
END LOOP;
-- 註意,上述迴圈執行完成後,Orable並沒有自動關閉游標,需要顯示關閉游標
IF v_cursor_for_msgs%ISOPEN THEN
dbms_output.put_line('CLOSING CURSOR');
CLOSE v_cursor_for_msgs;
END IF;
END;
顯示關閉游標
CLOSE cursor_name;
刪除存儲過程
基礎語法
DROP PROCEDURE procedure_name;
作者:授客
微信/QQ:1033553122
全國軟體測試QQ交流群:7156436
Git地址:https://gitee.com/ishouke
友情提示:限於時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額隨意,您的支持將是我繼續創作的源動力,打賞後如有任何疑問,請聯繫我!!!
微信打賞
支付寶打賞 全國軟體測試交流QQ群