1. 程式人生 > 其它 >PL/SQL 集合的初始化與賦值

PL/SQL 集合的初始化與賦值

對於集合型別,與單一的資料型別相比較而言,應該以一個整體的觀念來考慮集合,即是一批型別相同的資料組合而非單一的資料。因此集
合型別集合的宣告、賦值、初始化較之單一型別而言,有很大的不同。尤其是巢狀表與變長陣列,在賦值之前必須先初始化。當巢狀表和變長數
組在宣告時,它們都會自動地被設定成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等。 ———————————————— 版權宣告:本文為CSDN博主「Leshami」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。 原文連結:https://blog.csdn.net/leshami/article/details/7525891