合類型集合的聲明、賦值、初始化較之單一類型而言,有很大的不同。尤其是嵌套表與變長數組,在賦值之前必須先初始化。當嵌套表和變長數
組在聲明時,它們都會自動地被設置成NULL值。也就是嵌套表和變長數組中集合不存在任何元素,並不是針對它所擁有的元素。可以使用系統定
義的與集合類型同名的函數來初始化集合。我們必須顯式地調用構造函數爲每一個變長數組和嵌套表變量進行初始化操作(對於關聯數組來說,
是不需要使用構造函數進行初始化的)。
有關集合類型的描述請參考:
PL/SQL 聯合數組與嵌套表
PL/SQL 變長數組
PL/SQL --> PL/SQL記錄
一、聯合數組的賦值
聯合數組的不需要初始化,直接賦值即可。(後續講到的集合的初始化均指嵌套表與變長數組)
DECLARE
TYPE idx_loc_type IS TABLE OF VARCHAR2( 13 )
INDEX BY BINARY_INTEGER;
loc_tab idx_loc_type;
BEGIN
loc_tab( 1 ) := 'NEW YORK'; -->聯合數組不需要初始化,直接賦值即可
loc_tab( 2 ) := 'DALLAS';
DBMS_OUTPUT.put_line( ' loc_tab(1) value is ' || loc_tab( 1 ) );
DBMS_OUTPUT.put_line( ' loc_tab(2) value is ' || loc_tab( 2 ) );
END;
--------------------------------------------------------------------------------------------------------
DECLARE
TYPE idx_loc_type IS TABLE OF VARCHAR2( 13 )
INDEX BY BINARY_INTEGER;
loc_tab idx_loc_type;
v_counter INTEGER := 0;
BEGIN
FOR x IN ( SELECT loc FROM dept ) -->這裏通過for 循環得到loc的值
LOOP
v_counter := v_counter + 1; -->使用一個v_counter變量來控制聯合數組的下標
loc_tab( v_counter ) := x.loc; -->將得到的loc的值賦值給聯合數組中對應的一個下標位
DBMS_OUTPUT.put_line( ' loc_tab(' || v_counter || ') value is ' || loc_tab( v_counter ) );
END LOOP;
END;
二、集合的初始化與賦值
1、初始化的方法集合類型主要分爲三步來完成,一是聲明,二是初始化,三是賦值。初始化和賦值可以在聲明塊中完成,也可以在執行塊中完成。
collection_name collection_type:=collection_type(); -->初始化集合爲空(empty)
集合的初始化主要是通過構造函數(構造函數即是聲明類型是的類型名)來進行初始化,下面常用的初始化方法包括:
a、在聲明塊聲明集合,且在聲明塊中使用構造函數初始化爲空(empty)但非NULL,在執行塊中使用extend方式後進行賦值
b、在聲明塊聲明集合,在執行塊中使用構造函數初始化爲空(empty)但非NULL,在執行塊中使用extend方式後賦值
c、在聲明塊聲明集合,在執行塊中使用構造函數初始化時一併賦值
d、在聲明塊聲明集合,同時使用構造函數初始化並賦值,即三步合爲一步來完成
對於初始化爲空的集合(empty),後續需要使用extend方式來擴展容量,除非使用bulk collect into方式
2、集合賦值的方法
collection_name(subscript) := expression;
3、賦值時可能引起的異常
在下面幾種給集合元素賦值的情況下,可能會引起多種異常。
a、如果下標索引不存在或無法轉換成正確的數據類型,PL/SQL就會拋出預定義異常VALUE_ERROR。
通常,下標是一個整數。但關聯數組的下標也可以是VARCHAR2類型。
b、如果所給下標索引指向了一個未初始化的元素時,PL/SQL就會拋出SUBSCRIPT_BEYOND_COUNT異常。
c、如果集合被自動初始化爲空值並且程序引用了其中的一個元素,PL/SQL會拋出COLLECTION_IS_NULL異常。
4、元素的引用
collection_name(subscript)
可以把其中的表元素作爲參數傳遞。如verify_loc(nest_loc_tab(i)),verify_loc爲函數或過程。
三、集合的初始化與賦值引用示例
1、未初始化集合的情形
DECLARE
TYPE nest_loc_type IS TABLE OF VARCHAR2( 13 );
loc_tab nest_loc_type;
BEGIN
loc_tab( 1 ) := 'NEW YORK';
loc_tab( 2 ) := 'DALLAS';
DBMS_OUTPUT.put_line( ' loc_tab(1) value is ' || loc_tab( 1 ) );
DBMS_OUTPUT.put_line( ' loc_tab(2) value is ' || loc_tab( 2 ) );
END;
DECLARE
*
ERROR at line 1:
ora-06531: Reference to uninitialized collection -->收到了ora-06531錯誤提示,變長數組未初始化時會收到同樣的錯誤提示
ora-06512: at line 6
--------------------------------------------------------------------------------------------------------
2、集合爲NULL的判斷
DECLARE
TYPE nest_loc_type IS TABLE OF VARCHAR2( 13 );
loc_tab nest_loc_type;
BEGIN
IF loc_tab IS NULL THEN
DBMS_OUTPUT.put_line( 'Before initialization, the loc_tab is null.' );
-- While the collection is null, we cannot check its COUNT attribute.
-- DBMS_OUTPUT.PUT_LINE('It has ' || loc_tab.COUNT || ' elements.');
ELSE
DBMS_OUTPUT.put_line( 'Before initialization, the loc_tab is not null.' );
END IF;
loc_tab := nest_loc_type( ); --> initialize empty nest table
IF loc_tab IS NULL THEN
DBMS_OUTPUT.put_line( 'After initialization, the loc_tab is null.' );
ELSE
DBMS_OUTPUT.put_line( 'After initialization, the loc_tab is not null.' );
DBMS_OUTPUT.put_line( 'It has ' || loc_tab.COUNT || ' elements.' );
END IF;
END;
Before initialization, the loc_tab is null.
After initialization, the loc_tab is not null.
It has 0 elements.
PL/SQL procedure successfully completed.
--------------------------------------------------------------------------------------------------------
3、使用空構造函數在聲明時進行初始化
-->使用該方法初始化之後,表明嵌套表或變成數組是空的,但是非NULL,在執行塊再對其賦值
-->下面對變長數組進行初始化
DECLARE
TYPE varry_loc_type IS VARRAY( 10 ) OF scott.dept.loc%TYPE;
varry_loc_tab varry_loc_type := varry_loc_type( ); -->僅僅是在集合變量之後使用空構造函數
BEGIN
varry_loc_tab( 1 ) := 'NEW YORK'; -->儘管變長數組被初始化,但仍然不能直接賦值
varry_loc_tab( 2 ) := 'DALLAS'; -->這是由變長數組和嵌套表特性決定需要先做extend
DBMS_OUTPUT.put_line( ' varry_loc_tab(1) value is ' || varry_loc_tab( 1 ) );
DBMS_OUTPUT.put_line( ' varry_loc_tab(2) value is ' || varry_loc_tab( 2 ) );
END;
DECLARE
*
ERROR at line 1:
ora-06533: subscript beyond count
ora-06512: at line 6
--------------------------------------------------------------------------------------------------------
4、使用空構造函數在聲明時進行初始化,執行塊使用extend方式擴展後賦值
DECLARE
TYPE varry_loc_type IS VARRAY( 10 ) OF scott.dept.loc%TYPE;
varry_loc_tab varry_loc_type := varry_loc_type( ); -->僅僅是在集合變量之後使用空構造函數
BEGIN
varry_loc_tab.EXTEND; -->需要使用extend方式擴展集合容量
varry_loc_tab( 1 ) := 'NEW YORK';
varry_loc_tab.EXTEND; -->需要使用extend方式擴展集合容量
varry_loc_tab( 2 ) := 'DALLAS';
DBMS_OUTPUT.put_line( ' varry_loc_tab(1) value is ' || varry_loc_tab( 1 ) );
DBMS_OUTPUT.put_line( ' varry_loc_tab(2) value is ' || varry_loc_tab( 2 ) );
END;
--------------------------------------------------------------------------------------------------------
5、嵌套表的初始化,使用構造函數在執行塊直接初始化並賦值
DECLARE
TYPE nest_loc_type IS TABLE OF VARCHAR2( 13 );
loc_tab nest_loc_type;
BEGIN
loc_tab :=
nest_loc_type( 'NEW YORK' -->使用聲明時的類型nest_loc_type函數來進行初始化
,'DALLAS'
,'CHICAGO'
,'BOSTON' );
FOR i IN 1 .. loc_tab.COUNT
LOOP
DBMS_OUTPUT.put_line( 'loc_tab(' || i || ') value is ' || loc_tab( i ) );
END LOOP;
END;
--------------------------------------------------------------------------------------------------------
6、含有NOT NULL嵌套表的初始化
DECLARE
TYPE loc_type IS TABLE OF VARCHAR2( 13 ) NOT NULL; -->定義了NOT NULL約束條件
loc_tab loc_type;
BEGIN
loc_tab :=
loc_type( 'NEW york'
,NULL -->構造時傳遞了NULL值
,NULL
,'boston' );
FOR i IN 1 .. loc_tab.COUNT
LOOP
DBMS_OUTPUT.put_line( 'loc_tab(' || i || ') value is ' || loc_tab( i ) );
END LOOP;
END;
-->由於存在not null約束,初始化傳遞null值則收到錯誤提示
ERROR at line 8:
ora-06550: line 8, column 17:
pls-00567: cannot pass NULL to a NOT NULL constrained formal parameter
ora-06550: line 9, column 17:
pls-00567: cannot pass NULL to a NOT NULL constrained formal parameter
ora-06550: line 6, column 4:
pl/SQL: Statement ignored
--------------------------------------------------------------------------------------------------------
7、變長數組的初始化,使用構造函數直接初始化並賦值
-->變長數組的初始化與嵌套表一樣,可以使用構造函數直接初始化並賦值
DECLARE
TYPE varry_loc_type IS VARRAY( 10 ) OF scott.dept.loc%TYPE;
varry_loc_tab varry_loc_type;
BEGIN
varry_loc_tab :=
varry_loc_type( 'NEW YORK'
,'DALLAS'
,'CHICAGO'
,'BOSTON' );
FOR i IN varry_loc_tab.FIRST .. varry_loc_tab.LAST -->注意此處使用了集合方法中的函數first和last來控制循環步長
LOOP
DBMS_OUTPUT.put_line( 'varry_loc_tab(' || i || ') value is ' || varry_loc_tab( i ) );
END LOOP;
END;
--------------------------------------------------------------------------------------------------------
8、聲明時初始化(構造)、並賦值
DECLARE
TYPE nest_loc_type IS TABLE OF VARCHAR2( 13 ) NOT NULL;
nest_loc_tab nest_loc_type := nest_loc_type( 'NEW YORK', 'DALLAS', 'CHICAGO' ); -->在聲明時直接初始化並賦值
BEGIN
FOR i IN 1 .. nest_loc_tab.COUNT -->注意此處調用了集合操作方法中的count函數
LOOP
DBMS_OUTPUT.put_line( 'nest_loc_tab(' || i || ') value is ' || nest_loc_tab( i ) );
END LOOP;
END;
--------------------------------------------------------------------------------------------------------
9、SQL語句中使用構造函數
CREATE OR REPLACE TYPE mail_type IS TABLE OF VARCHAR2( 100 ); -->創建一個嵌套表類型
CREATE TABLE tb_tmp -->創建表tb_tmp
(
empno NUMBER( 4 )
,ename VARCHAR2( 10 )
,mail mail_type -->列mail的類型爲mail_type
)
NESTED TABLE mail -->注意此處需要指定嵌套表的存儲方式
STORE AS mail_tab;
INSERT INTO tb_tmp
SELECT 8888, 'Jack', mail_type( '[email protected]', '[email protected]' ) FROM dual; -->插入數據時需要使用構造函數
10、集合與集合之間的賦值
-->下面的例子聲明瞭兩個變長數組last_name_type和surname_type
DECLARE
TYPE last_name_type IS VARRAY( 3 ) OF VARCHAR2( 64 );
TYPE surname_type IS VARRAY( 3 ) OF VARCHAR2( 64 );
-->下面聲明瞭兩個相同類型的變長數組併爲其賦值,group1和group2使用了相同的構造函數
group1 last_name_type := last_name_type( 'Jones', 'Wong', 'Marceau' );
group2 last_name_type := last_name_type( 'Klein', 'Patsos', 'Singh' );
-->下面的group3使用了surname_type作爲類型
group3 surname_type := surname_type( 'Trevisi', 'Macleod', 'Marquez' );
BEGIN
group1 := group2; -- >group1 和group2之間可以相互賦值
-- group3 := group2; -->raises an error PLS-00382: expression is of wrong type
END;
-- >group3和group2則不能賦值,因爲兩者爲不同的數據類型
-->儘管last_name_type與surname_type類型定義是相同的,但其實例化後,其集合變量不能互相賦值
--------------------------------------------------------------------------------------------------------
11、使用NULL值集合爲集合賦值
DECLARE
TYPE nest_loc_type IS TABLE OF VARCHAR2( 30 );
nest_loc_tab nest_loc_type := nest_loc_type( 'NEW YORK', 'DALLAS', 'CHICAGO' );
empty_nest_loc_tab nest_loc_type; --> 嵌套表empty_nest_loc_tab沒有初始化,此時被自動置爲NULL
BEGIN
IF nest_loc_tab IS NOT NULL THEN
DBMS_OUTPUT.put_line( 'OK, at first nest_loc_tab is not null.' );
END IF;
nest_loc_tab := empty_nest_loc_tab; -->將empty_nest_loc_tab的值(NULL)嵌套表賦值給nest_loc_tab
IF nest_loc_tab IS NULL THEN --> 此時nest_loc_tab被置爲NULL,相當於沒有初始化
DBMS_OUTPUT.put_line( 'OK, now nest_loc_tab has become null.' );
END IF;
nest_loc_tab := nest_loc_type( 'NEW YORK', 'DALLAS', 'CHICAGO' ); -->此時如果後續需要使用該嵌套表,應重新初始化它
END;
12、記錄類型的變長數組的初始化、賦值與元素引用
DECLARE
TYPE emp_name_rec IS RECORD -->聲明一個基於用戶定義的記錄類型
(
firstname employees.first_name%TYPE
,lastname employees.last_name%TYPE
,hiredate employees.hire_date%TYPE
);
TYPE emplist_arr IS VARRAY( 10 ) OF emp_name_rec; -->聲明一個基於記錄的變長數組,且最大尺寸爲10
seniorsalespeople emplist_arr; -->聲明基於記錄的變長數組變量
CURSOR c1 IS -->聲明遊標,其列前面的記錄類型相對照
SELECT first_name, last_name, hire_date FROM employees;
TYPE nameset IS TABLE OF c1%ROWTYPE; -->聲明基於遊標的記錄類型
seniorten nameset; -->聲明基於遊標記錄類型的變量
endcounter NUMBER := 10; -->變量endcounter計數器
BEGIN
seniorsalespeople := emplist_arr( ); -->初始化集合
SELECT first_name, last_name, hire_date -->從表中提取數據,且使用了BULK COLLECT INTO方式
BULK COLLECT INTO seniorten
FROM employees
WHERE job_id = 'SA_REP'
ORDER BY hire_date;
IF seniorten.LAST > 0 THEN
IF seniorten.LAST < 10 THEN -->如果小於10,則縮小變長數組的最大尺寸
endcounter := seniorten.LAST;
END IF;
FOR i IN 1 .. endcounter -->使用循環將遊標類型變量中的元素逐條賦值給記錄的變長數組變量seniorsalespeople並輸出
LOOP
seniorsalespeople.EXTEND( 1 );
seniorsalespeople( i ) := seniorten( i );
DBMS_OUTPUT.
put_line(seniorsalespeople(i).lastname||', '||seniorsalespeople(i).firstname||', '||seniorsalespeople(i).hiredate);
END LOOP;
END IF;
END;
上面的這個例子是一複合的數據類型,比單一的集合類型更爲複雜。我們知道集合通常是針對單列多行數據而言,而記錄則是單行多列。兩
者的綜合,則此時就等同於數據庫中的一張二維表。示例中首先聲明用戶定義的記錄類型以及變長數組,接下來基於這兩者聲明變量。後面使用
基於遊標的記錄類型來申明變量seniorten與前面的變量seniorsalespeople相對應,seniorten變量用於存儲後面的SQL語句批量提取的數據集。
後面使用了一個for循環來從seniorten變量取出數據並賦值爲seniorsalespeople。注:在這個例子中變量seniorten存儲的記錄超出了變長數組
的最大尺寸,因此後續的被丟棄。
13、記錄類型的嵌套表的初始化、賦值與元素引用
DECLARE
TYPE emp_name_rec IS RECORD
(
firstname employees.first_name%TYPE
,lastname employees.last_name%TYPE
,hiredate employees.hire_date%TYPE
);
TYPE emplist_tab IS TABLE OF emp_name_rec;
seniorsalespeople emplist_tab;
endcounter NUMBER := 10;
TYPE empcurtyp IS REF CURSOR; -->聲明遊標變量類型
emp_cv empcurtyp; -->聲明遊標變量類型的變量emp_cv
BEGIN
OPEN emp_cv FOR
SELECT first_name, last_name, hire_date
FROM employees
WHERE job_id = 'SA_REP'
ORDER BY hire_date;
FETCH emp_cv
BULK COLLECT INTO seniorsalespeople; -->使用BULK COLLECT INTO 方式一次將數據加載到seniorsalespeople變量
CLOSE emp_cv;
IF seniorsalespeople.LAST > 0 THEN
IF seniorsalespeople.LAST < 10 THEN
endcounter := seniorsalespeople.LAST;
END IF;
FOR i IN 1 .. endcounter
LOOP
DBMS_OUTPUT.
put_line(seniorsalespeople(i).lastname||', '||seniorsalespeople(i).firstname||', '||seniorsalespeople(i).hiredate);
END LOOP;
END IF;
END;
-->Author : Robinson Cheng
-->Blog : http://blog.csdn.net/robinson_0612
上面的這個例子稍有不同於前面的例子,使用的基於用戶定義記錄的嵌套表方式,且使用了遊標變量類型。在fetch時直接將數據fetch 到
集合變量seniorsalespeople中,此時不需要使用extend方式來擴展。
四、總結
1、對於集合類型在爲其賦值之前,需要對集合進行初始化。而聯合數組不需要初始化而直接進行賦值。2、在聲明嵌套表與變長數組時,這些集合類型會被自動置爲NULL,即集合不存在任何元素。而不是集合中的元素爲NULL。
3、集合類型的初始化方法是是直接使用聲明時的同名類型構造器來對集合進行初始化。
4、集合類型的初始化方法有多種,可以在聲明時初始化,也可以在執行塊初始化。
5、集合類型的賦值可以在聲明塊聲明時賦值,也可以在執行塊執行時使用extend方式擴展後再賦值。
6、集合類型的初始化過程連同賦值可以在聲明集合的同時使用構造函數直接進行初始化並賦值,從而一步完成。
7、SQL語句中也需要使用構造函數來操作集合數據。
8、注意本文描述中的集合初始化後爲空的理解。初始化後爲空表示的是一個空(empty)集合,而未初始化時是NULL(UNKNOWN)值。
9、集合與集合之間的賦值需要聲明的爲同一類型的變量之間纔可以賦值,否則收到錯誤提示。
10、注意理解複合類型之間(嵌套表和變長數組中嵌有PL/SQL記錄)的變量元素間的傳遞以及集合方法BULK COLLECT INTO,LAST,EXTEND等。
--==========================================================================================
聯合數組無需初始化 www.2cto.com