Oracle 存儲過程學習總結

来源:https://www.cnblogs.com/shouke/archive/2022/10/23/16819867.html
-Advertisement-
Play Games

創建/更新存儲過程 基礎基礎用法 創建/修改無參存儲過程 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 表示輸入輸出參數(註:都不區分大小寫)

註意:

  1. 存儲過程參數數據類型不能指定長度
  2. 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群  
              


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • top命令可以用來監控伺服器CPU、記憶體的運行情況,是Linux一個經常使用到的命令。 基本用法 第一行 顯示當前系統運行信息,系統當前時間是23:23:21,運行了315days,當前有2個用戶登錄(2 users),系統平均負載壓力情況(load average)為0.08(1min的平均負載壓 ...
  • ansible常用模塊 一、ansible常用模塊使用詳解 ansible常用模塊有: ping yum template copy user group service raw command shell script ansible常用模塊raw、command、shell的區別: shell模 ...
  • ansible常用模塊的介紹與使用 ansible常用模塊有: ping yum template copy user group service raw command shell script ansible常用模塊raw、command、shell的區別: shell模塊調用的/bin/sh指 ...
  • 痞子衡嵌入式半月刊: 第 65 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 ...
  • NFS: Network File System 網路文件系統,是一個文件系統,不是一種協議類型。使用 NFS,用戶和程式可以像訪問本地文件一樣訪問遠端系統上的文件。 說明: NFS是內核提供的一個功能,文件系統的管理不是由應用程式管理,而是操作系統內核在管理。 硬碟上常見的文件系統:ext4、xf ...
  • topaz clean 3 Mac版是款簡單實用的去處圖像噪點的濾鏡插件;它擁有非常獨特的演算法,可以支持用戶快速的去除大面積或者不相同種類靜態圖片還是那個面的噪點,支持進行細節圖像的保留;還擁有可以將照片快速的變成手會風格的圖片,使您的圖片更加的具有真實性。 詳情:Topaz Clean 3 for ...
  • Bomb Lab 引言:主要任務是“拆炸彈”。所謂炸彈,其實就是一個二進位的可執行文件,要求輸入六個字元串,每個字元串對應一個phase。如果字元串輸入錯誤,系統就會提示BOOM!!!解決這次實驗需要將二進位文件反彙編,通過觀察理解彙編語言描述的程式行為來猜測符合條件的字元串。可以看出該可執行程式要 ...
  • 前言:在zookeeper學習的時候,執行jsp命令查看zookpper運行狀態的時候發現報錯: -bash: jps: command not found 翻閱了一大批文章,不是東拼西湊,就是缺斤少兩,於是乎,本人萌生了第一次寫博客的想法,復盤的同時,順便記錄一下此次踩坑的經過,開始吧,GOGOG ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...