共計 3456 個字符,預計需要花費 9 分鐘才能閱讀完成。
自動寫代碼機器人,免費開通
這篇文章給大家分享的是有關 oracle 合并多個 sys_refcursor 的案例的內容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。
一、背景
在數據開發中,有時你需要合并兩個動態游標 sys_refcursor。
開發一個存儲過程 PROC_A, 這個過程業務邏輯相當復雜,代碼篇幅較長。一段時間后要開發一個 PROC_B, 要用 PROC_A 同樣的邏輯, 而且在這個過程中,還要循環調用 PROC_A 這個過程。擺在你面前的有兩個選擇。
打開 PL/SQL, 仔細的讀 PROC_A 這個過程,一直到明白了所有的邏輯,然后在自己的過程中重寫這個邏輯。
直接復制 PROC_A 這個過的代碼過來,多寫極端。還是業界標準大法好
針對循環調用的,建立一個臨時表,循環插入數據到臨時表(但這里還有一個問題,每次返回的游標可能列都不相同,建立臨時表就顯得復雜了)
好吧,這個新的過程是完成了,可是看上去,它更復雜了,代碼量更大了。完全不能接受,必須改改!
這時,已經默默打開了 ORACLE 官方幫助文檔 https://docs.oracle.com/cd/B19306_01/index.htm,尋找一個可行的辦法,最終目標標是要解析,整合,合并 游標 sys_refcursor
二、思路
經過搜索查詢,找到以下可行的方案
序列化 sys_refcursor 為 xml 文檔,ORACLE 對 xml 支持還不錯,12C 已經有 JSON 格式了
使用 ORACLE xml 解析的方法,對序列化的 xml 文檔,添加、刪除、修改
轉換為內存表,通過游標返回查詢的結果
為此你需要掌握的知識有
使用 Dbms_Lob 個 package 操作 clob 類型數據,因為解析后的游標可能用 varchar2 是裝不下的,幫助地址 https://docs.oracle.com/cd/E11882_01/timesten.112/e21645/d_lob.htm#TTPLP600。
重點掌握 Oracle 類型 xmltype 如何使用 https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/t_xml.htm#BABHCHHJ
三、實現
從上邊的幫助文檔中,知道 xmltype 的構造函數中可以直接傳入游標 xmltype(refcursor)從而得到一個 xmltype,調用 xmltype 的 getClobVal 方法,可得到序列化的結果,所以它的結構是這樣的
?xml version= 1.0 ?
ROWSET
ROW
COLUMNNAME1 /COLUMNNAME1
COLUMNNAME2 /COLUMNNAME2
... ... /...
/ROW
/ROWSET
所以,如果需要合并兩個數據列相同游標,只需要提取 DOM 中的 ROW 節點數據保存到定義的 clob 字段中去。
提取 dom 中片段,采用標準的 xpath 語法,/ROWSET/ROW 這里提取 ROW 信息
Declare
x xmltype;
rowxml clob;
mergeXml clob;
ref_cur Sys_Refcursor;
ref_cur2 Sys_Refcursor;
ref_cur3 Sys_Refcursor;
begin
open ref_cur for
select F_USERNAME, F_USERCODE, F_USERID
from Tb_System_User
where F_userid = 1;
Dbms_Lob.createtemporary(mergeXml, true);
Dbms_Lob.writeappend(mergeXml, 8, ROWSET
x := xmltype(ref_cur);
Dbms_Output.put_line( ===== 完整的 REFCURSOR 結構 =====
Dbms_Output.put_line(x.getClobVal());
Dbms_Output.put_line( ===== 只提取行信息 =====
rowxml := x.extract(/ROWSET/ROW).getClobVal(0, 0);
Dbms_Output.put_line(rowxml);
Dbms_Lob.append(mergeXml, rowxml);ROWSET
open ref_cur2 for
select F_USERNAME, F_USERCODE, F_USERID
from Tb_System_User
where F_userid = 1000;
x := xmltype(ref_cur2);
rowxml := x.extract(/ROWSET/ROW).getClobVal(0, 0);
Dbms_Lob.append(mergeXml, rowxml);
Dbms_Lob.writeappend(mergeXml, 9, /ROWSET
Dbms_Output.put_line( ===== 合并后的信息 =====
Dbms_Output.put_line(mergeXml);
end;
執行這段代碼輸出的結果是這樣的
===== 完整的 REFCURSOR 結構 =====
?xml version= 1.0 ?
ROWSET
ROW
F_USERNAME 系統管理員 /F_USERNAME
F_USERCODE admin /F_USERCODE
F_USERID 1 /F_USERID
/ROW
/ROWSET
===== 只提取行信息 =====
ROW
F_USERNAME 系統管理員 /F_USERNAME
F_USERCODE admin /F_USERCODE
F_USERID 1 /F_USERID
/ROW
===== 合并后的信息 =====
ROWSET ROW
F_USERNAME 系統管理員 /F_USERNAME
F_USERCODE admin /F_USERCODE
F_USERID 1 /F_USERID
/ROW
ROW
F_USERNAME 黃燕 /F_USERNAME
F_USERCODE HUANGYAN /F_USERCODE
F_USERID 1000 /F_USERID
/ROW
/ROWSET
從上邊打印的結果看,我們已經成功的將兩個游標 ref_cur 和 ref_cur2 中我們需要的列信息合并到了一個 xml 文檔中。那么接下了,我們就需要通過解析這個 xml 并返回一個新的 sys_refcursor, 這里你有必要了解以下 oracle xmltable 的用法 (https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions228.htm) 接上邊代碼
Dbms_Output.put_line(mergeXml);
open ref_cur3 for
select *
from xmltable(/ROWSET/ROW Passing xmltype(mergeXml) Columns
F_USERNAME varchar2(100) path F_USERNAME ,
F_USERCODE varchar2(100) path F_USERCODE
簡單說明下 xmltable 構造函數
聲明 xpath,指明你需要解析的 dom 在哪里,比如從根找到 ROW /ROWSET/ROW
指明你要查詢的 xmltype
定義轉換列,比如把 ROW 下邊的 F_USERNAME 這個節點值,映射到游標列 F_USERNAME 這個列中
附:sys_refcursor 和 cursor 優缺點比較
優點比較
優點一:sys_refcursor,可以在存儲過程中作為參數返回一個 table 格式的結構集(我把他認為是 table 類型,容易理解,其實是一個游標集),cursor 只能用在存儲過程,函數,包等的實現體中,不能做參數使用。
優點二:sys_refcursor 這東西可以使用在包中做參數,進行數據庫面向對象開放。哈哈。我喜歡。cursor 就不能。
缺點比較:
缺點:sys_refcursor 不能用 open,close,fetch 進行操作。不好學,難理解。
cursor 可以用 open,close,fetch 操作,容易學,易懂
感謝各位的閱讀!關于“oracle 合并多個 sys_refcursor 的案例”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
向 AI 問一下細節