存儲過程因其執行效率高、與事務處理的結合、運行更安全等優點,在數據庫應用程序中被廣泛采用。PL/SQL是用於從各種環境中訪問Oracle數據庫的一種編程語言,它與數據庫服務器集成在一起,PL/SQL編寫的存儲過程編譯效率高,網絡系統開銷小,同時PL/SQL直觀性好,是大多數人的選擇。
以Number、Varchar等基本標量類型為輸出參數的PL/SQL存 儲過程,每個輸出參數只能返回一個對應值。而在實際數據庫應用程序中,尤其是在進行系統綜合查詢統計時,往往需要返回二維數組或結果集,這時應考慮在存儲 過程中使用集合這種數據結構。對於集合,我們可以一次把許多元素作為一個整體進行操作,也可以對集合中的單個元素進行操作,使用方便、靈活。
2 PL/SQL存儲過程
2.1 索引表作為參數
索引表是無約束的,其大小的唯一限制(除可用內存外)就是它的關鍵字BINARY_INTEGER類型所能表示數值的約束(-2147483647...+2147483647),其元素不需要按任何特定順序排列。在聲明時,我們不需要指定其大小,而且對索引表的元素可以直接賦值,不用初始化,可見使用索引表極其方便。
我們可以在PL/SQL語句塊中定義索引表,但作為輸出參數的索引表,必須要在包(package)裡定義,方法如下:
create or replace package out_param is
---- 定義了元素是varchar2類型的一個索引表類型
type out_index_table_typ is table of varchar2(50) index by binary_integer;
end out_param;
接下來就可以在pl/sql存儲過程裡引用在包裡定義的索引表類型:
create or replace procedure testPro1(in_param in varchar2,o_table out out_param. out_index_table_typ ) is
begin
-------這裡略去程序體
end testPro1;
其中,返回的索引表類型前必須用包名加上句點來引用out_param. out_index_table_typ
索引表與數據庫表很形似,有key和value兩列,但它不是真正的數據庫表,不可以存儲到數據庫中。因此索引表不能使用SQL進行操作,這樣它的內容不能通過一個標准的SELECT語句返回游標得到。這一點與嵌套表有很大不同。
2.2 可變數組作為參數
可變數組和另外兩種集合類型不同,其元素在內存中是連續存儲的,且在大小方面有一個固定的上界。聲明時需要指定該數組中元素的最大數目(可變數組的大小可以用EXTEND方法來增加,但不能被擴展超過所聲明的極限大小)。
可變數組的元素被賦值之前,必須使用構造器進行初始化。元素插入數組時應從索引1開始,連續插入。
可變數組的定義方法如下:
create or replace type testArray is varray(5) of number(3)
PL/SQL存儲過程裡調用可變數組作為輸出參數:
create or replace function getTestArray return testArray
as
o_data testArray:= testArray ();
begin
for v_count in 1..5 loop
o_data.extend;
o_data(v_count):= v_count;
end loop;
return o_data;
end;
2.3 嵌套表作為輸出參數
存儲過程中使用嵌套表,並不是直接將嵌套表作為輸出參數,而是對嵌套表"造型"後以游標形式輸出。嵌套表的基本功能與索引表相同,但嵌套表可以使用SQL進 行操作,其內容可通過SELECT 語句查詢並"造型"後以游標形式返回。在大多數的查詢統計中,常常需要返回結果集,這時使用嵌套表就尤其方便。筆者在開發過程中深刻體會到使用對象嵌套表 可以解決絕大多數的查詢統計問題。下面著重介紹如何在存儲過程裡利用對象類型的嵌套表。
對於任意的統計分析表格,我們可以將其簡化成下面的輸出形式:
統計項目1
統計項目2
統計項目3
統計項目4
名稱1
名稱2
這樣我們把每一行看作是一個對象實例,該行的每一列則可以看作是該對象的一個屬性,下面通過構造對象,然後對包含對象的嵌套表進行造型,返回游標得到結果集。
首先構造統計對象如下:
create or replace type TestObj as object
(
vname varchar2(20), --名稱
item1 number, --統計項目1
item2 number, --統計項目2
item3 number, --統計項目3
item4 number --統計項目4
);
構造包含對象類型的嵌套表:
create or replace type TestNestTable as table of TestObj;
定義對索引表"造型"後的輸出的游標類型:
create or replace package out_param is
type out_cur is ref cursor;
下面是嵌套表作為輸出參數的存儲過程:
create or replace procedure testPro2(o_cur out out_param.out_cur ) is
---- 包含對象的嵌套表變量的聲明
v_objTable TestNestTable:= TestNestTable ();
begin
--嵌套表變量的使用
v_objTabl.extend;
v_objTable(1):= TestObj(‘張三',12,123,123,34);
v_objTabl.extend;
v_objTable(2):= TestObj(‘李四,22,223,223,234);
--對嵌套表進行"造型"返回游標
open o_cur for select * from Table(cast (v_objTable as TestNestTable) );
end testPro2;
3 結束語
使用索引表和可變數組,可將返回的集合映射成Java數組。由於索引表會自動分配空間,在聲明時不需要指定其大小,而且不需要初始化,使用起來比較方便。但是索引表作為輸出參數只能使用oci驅動(返回游標時,可以用瘦客戶驅動也可以用oci驅動),所需要的動態連接庫文件(ocijdbc9.dll)要在環境變量裡進行設置(例如:path=D:\oracle\ora90\BIN),在不同的環境下OCI驅動還可能出現類裝載異常,所以返回索引表盡管方便,但偶爾會出現意想不到的錯誤。可變數組映射成Java數組簡單,對於返回小數據量的結果,也是不錯的選擇,但使用可變數組作為輸出參數,聲明時必須限定該數組的大小上限,並且需使用構造器初始化。
使用嵌套表,可以對嵌套表進行SQL操作,其內容能通過對標准的SELECT 語句造型後可轉化為游標輸出。而且嵌套表的內容相當於session變量,當斷開連接後即釋放內存,但同樣存在需要初始化和擴展的問題。
綜上所述,究竟采用索引表、嵌套表和可變數組中哪一種作為存儲過程的輸出要看具體的要求和開發環境。有一點我們需要注意,如果返回的數據量較大,以數組形式 返回,則需一次性取回所有結果,在PL/SQL裡為所有結果分配空間並復制,然後將這些數據通過網絡發送到客戶端,客戶端也同樣需要分配空間接受這些數 據;而采用游標形式,只要返回一個指針,然後分批返回結果(可自定義每次返回記錄的條數),而不是一次性返回所有結果,因此在客戶端不需分配大塊的空間存 放所有結果。可見,對於大數據量的應用程序,返回游標程序運行效率會更高。