oracle collection

Collections Overview

一、Types of Collections

    1、Associative arrays 數組
      它是同種類型的一維、無邊界的稀疏集合,只能用於 PL/SQL。
      DECLARE TYPE t_name IS TABLE OF varchar2(10) INDEX BY PLS_INTEGER; --創建 Collection
              i_name t_name;      --創建 instance
              l_row PLS_INTEGER;
      BEGIN
              i_name(202020):='aaa';
              i_name(-125):='bbb';
              i_name(88):='ccc';              --賦值,row number 可以爲任何整數,且可以跳躍(稀疏的),也不用按照順序賦值,其內部最終按照 row number 排序
              l_row := i_name.FIRST;          --返回第一個 row number
              l_row := i_name.NEXT (l_row);   --返回 l_row 之後的一個 row number,會自動跳過爲空的行
              DBMS_OUTPUT.put_line (i_name (l_row)); --返回指定行的值
      END;
   
    2、Nested tables 嵌套表
      也是同種類型的一維無邊界集合。起初它是密集的,經過刪除操作會變成稀疏。它可以在 PL/SQL 和 Database(某一列爲一個嵌套表)中被定義。它是 multisets 的,也就是說 nested table 中的元素沒有內在的順序
      DECLARE TYPE t_name IS TABLE OF varchar2(10); --創建 Collection,和 Associative arrays 相差一個 INDEX BY
              i_n1 t_name := t_name(); --創建 instance,需要使用構造函數
              i_n2 t_name := t_name();
              i_n3 t_name := t_name();
      BEGIN
              i_n1.EXTEND(2); --賦值前要分配空間
              i_n1(1):='aaa'; --賦值,row number 最小爲 1,最大爲 EXTEND 分配的空間數,可以跳過某個行不分配則爲 null
              i_n1(2):='bbb';
              i_n2.EXTEND;     --分配一個空間
              i_n2(1):='bbb';
              i_n3 := i_n1 MULTISET EXCEPT i_n2; --10g 開始提供的功能,將 i_n1 中除去 i_n2 的值,賦值給 i_n3
              FOR l_row IN i_n1.FIRST .. i_n1.LAST --從行首到行尾,依次輸出
              LOOP
                 DBMS_OUTPUT.put_line (i_n1(l_row));
              END LOOP;
      END;

    3、VARRAYs 變量數組
      VARRAYs (variable-sized arrays),也是同種類型的一維集合。但它是有界且不稀疏的。在定義 VARRAYs 時要指定它的最大範圍。VARRAYs 也可以在 PL/SQL 和 Database 中被定義,但它其中的元素是有順序的。
      DECLARE TYPE t_name IS VARRAY (2) OF VARCHAR2 (10); --創建 Collection,需要指定最大範圍
              i_n1 t_name := t_name(); --創建 instance,需要使用構造函數
      BEGIN
              i_n1.EXTEND(2); --賦值前要分配空間,不能超過最大範圍
              i_n1(1):='aaa'; --賦值,row number 最小爲 1,最大爲 EXTEND 分配的空間數
              i_n1(2):='bbb';
      END;
    
二、Where You Can Use Collections

    1、作爲 record 的成分
    2、作爲程序的參數
      由於 Oracle 沒有預定的集合類型,當作爲參數使用前,需要定義集合類型:
        1.用 CREATE TYPE 定義 schema-level 類型
        2.在 package specification 中聲明
        3.在外層作用域定義
    3、作爲函數的返回值
      1.返回集合直接賦值給 collection variable,這時這個 collection variable 不需要初始化
      2.將返回集合中的一個元素賦值給一個類型兼容的變量
          variable_of_element_type := function() (subscript);
          如果函數返回空值,在賦值時會產生 COLLECTION_IS_NULL 異常,應該捕獲並適當處理該異常
    4、作爲數據庫表的列
      當使用 nested table datatype 作爲列時,必須指定 store table 的名字:
        CREATE TABLE personality_inventory (
           person_id NUMBER,
           favorite_colors Color_tab_t,
           date_tested DATE,
           test_results BLOB)
        NESTED TABLE favorite_colors STORE AS favorite_colors_st;
      不能對 store table 進行維護或者試圖直接查詢、存儲數據,只能通過 outer table 來獲取它的屬性。也不能指定它的 storage parameters,它繼承與 outermost table。
      nested tables 和 VARRAYs 的區別在於,VARRAY 和其它數據一起存於表內,而 nested table 存於表外,VARRAY 適合 "small" arrays,nested table 適合 "large" arrays。
    5、作爲 object type 的屬性
  
三、Choosing a Collection Type

    1.如果要用稀疏 array,那麼只能使用 associative array,雖然可以先分配 nested table 在刪除其中的項目,但效率很低
    2.如果在 PL/SQL 中要用負數的下標,只能用 associative array
    3.如果使用 10g,希望使用 set 層面的操作,那麼選擇 nested tables + MULTISET EXCEPT 的方法
    4.如果要限制存儲的行數,使用 VARRAYs
    5.如果要在 column 中存儲大數據量集合,那麼使用 nested table,Oracle可以使用單獨的表來存儲它
    6.如果你想將存在 collection column 中的數據保持原有順序,並且數據量很小,可以使用 VARRAY,小的概念可以按照 BLOCK 的大小來判斷,如果數據量超過一個 BLOCK,將會產生行連接
    7.還有些情況適合使用 VARRAY:you don't want to worry about deletions occurring in the middle of the data set; your data has an intrinsic upper bound; or you expect, in general, to retrieve the entire collection simultaneously.


Collection Methods (Built-Ins)

Collection methods 只能用於 PL/SQL,不能在 SQL 中使用

1、The COUNT Method
    用於計算 associative array, nested table, or VARRAY 中元素的個數,使用 DELETEd or TRIMmed 將減少 COUNT
    定義:
      FUNCTION COUNT RETURN PLS_INTEGER;
    對於初始化了,但不包含元素的 collection 返回 0,對於空的 associative array 也返回 0
    如果對未初始化的 nested table or a VARRAY 使用 COUNT 將返回 COLLECTION_IS_NULL 異常,associative arrays 無需初始化,故不會返回異常
  
2、The DELETE Method
    DELETE 用於刪除 collection 中的一個、多個或者全部元素:
      1.不加參數,刪除所有元素,對於 VARRAYs 只能使用這種方法,因爲 VARRAYs 不能使稀疏的,要刪除一行,只能用 TRIM 刪除最後一行
      2.DELETE(i) 刪除第 i 行
      3.DELETE(i,j) 刪除第 i~j 行
    對於使用參數的 DELETE,其實使用一個佔位符來代替刪除的元素,以後還可以爲它們再賦值,賦值之後在 COUNT 中又開始計數。從物理角度來考慮,PL/SQL 只有在刪除足夠多數量的元素,以至於可以釋放 entire page of memory 時才釋放內存,但不加參數的 DELETE 是立即釋放所有內存的
    定義:
      PROCEDURE DELETE;
      PROCEDURE DELETE (i [BINARY_INTEGER | VARCHAR2(size_limit)]);
      PROCEDURE DELETE (i [BINARY_INTEGER | VARCHAR2(size_limit)],
                        j [BINARY_INTEGER | VARCHAR2(size_limit)]);
    如果 i,j 超出範圍,不會出現異常,只是刪除在範圍內的,超出部分忽略
    如果對未初始化的 nested table or a VARRAY 使用 DELETE 將返回 COLLECTION_IS_NULL 異常
  
3、The EXISTS Method
    判斷 collection 中的指定行是否存在,如果以前存在,後來被 DELETE 了,那也返回 false
    定義:
      FUNCTION EXISTS (i IN [BINARY_INTEGER | VARCHAR2(size_limit)]) RETURN BOOLEAN;
    
4、The EXTEND Method
    用於爲 nested table or VARRAY 分配空間
      1.不加參數,分配一個 null element
      2.EXTEND(n),分配 n 個 null element
      3.EXTEND(n,i),分配 n 個和第 i 值相同的 element,這對於有 NOT NULL 限制的 element 是必要的
    定義:
      PROCEDURE EXTEND (n PLS_INTEGER:=1);
      PROCEDURE EXTEND (n PLS_INTEGER, i PLS_INTEGER);
    如果用 DELETEd or TRIMmed 刪除了 collection 的最後一個元素,再 EXTEND 時,會跳過這個,在後面分配空間
    如果對未初始化的 nested table or a VARRAY 使用 DELETE 將返回 COLLECTION_IS_NULL 異常,如果 EXTEND 超過 VARRAY 的最大限制,將返回 SUBSCRIPT_BEYOND_LIMIT 異常
  
5、The FIRST and LAST Methods
    分別返回 COLLECTION 中可用的最低和最高下標,被 DELETE 的不會顯示
    定義:
      FUNCTION FIRST RETURN PLS_INTEGER;
      FUNCTION LAST RETURN PLS_INTEGER;
    對於初始化了,但沒有元素的 COLLECTION,都返回 null;對於至少有一個 element 的 VARRAYs,FIRST 總爲 1,LAST 總等於 COUNT
    如果對未初始化的 nested table or a VARRAY 使用 FIRST and LAST 將返回 COLLECTION_IS_NULL 異常
  
6、The LIMIT Method
    返回 VARRAY 的最大數目限制,如果用於 nested tables or to associative arrays 將返回 NULL
    定義:
      FUNCTION LIMIT RETURN PLS_INTEGER;
    如果對未初始化的 nested table or a VARRAY 使用 LIMIT 將返回 COLLECTION_IS_NULL 異常
  
7、The PRIOR and NEXT Methods
    用於遍歷 COLLECTION 中的內容
    定義:
      FUNCTION PRIOR (i [BINARY_INTEGER | VARCHAR2(size_limit)])
          RETURN [BINARY_INTEGER | VARCHAR2(size_limit)];
      FUNCTION NEXT (i [BINARY_INTEGER | VARCHAR2(size_limit)])
          RETURN [BINARY_INTEGER | VARCHAR2(size_limit)];
    如果應用於初始化了但爲空的 COLLECTION 時,返回 null;如果 i 大於等於 COUNT,則 NEXT 返回 null;如果 i 小於等於 FIRST,則 PRIOR 返回 null
    就目前來說,如果 i 大於 COUNT,則 PRIOR 返回 LIMIT;如果 i 小於 FIRST,則 NEXT 返回 LIMIT,但以後的版本不知道是不是這樣了
    如果對未初始化的 nested table or a VARRAY 使用 PRIOR and NEXT 將返回 COLLECTION_IS_NULL 異常
  
8、The TRIM Method
    由於刪除 nested table or VARRAY 末尾的 n 行,如果不加參數,刪除最後一行,如果用於 associative array 將產生編譯時錯誤
    DELETE and TRIM 聯合使用將產生重複刪除的問題,比如 DELETE 刪除最後一行之後,再用 TRIM 刪除最後 n 行時,其實 TRIM 重複操作了被 DELETE 刪除的那行(因爲刪除之後變成了佔位符),使得實際上少刪除一行,因此 Oracle 建議兩者不要混合使用
    定義:
      PROCEDURE TRIM (n PLS_INTEGER:=1);
    如果 n 爲 null,TRIM 不做任何事情
    如果對未初始化的 nested table or a VARRAY 使用 TRIM 將返回 COLLECTION_IS_NULL 異常
    如果 TRIM 的 n 大於實際存在的元素個數,那麼返回 SUBSCRIPT_BEYOND_COUNT 異常
  
  
Working with Collections

一、Declaring Collection Types

    兩種聲明方法:
      1.在 PL/SQL 中使用 TYPE 語句,如果定義在 package 中,對於使用該類型的用戶要將 package 的 EXECUTE 權限授予該用戶
      2.對於 nested table type or VARRAY type 在 schema-level 使用 CREATE TYPE 命令,並將該類型的 EXECUTE 權限授予需要使用的用戶
    
    Declaring an associative array collection type
      TYPE table_type_name IS TABLE OF datatype [ NOT NULL ]
         INDEX BY index_type;
      datatype 包括:
        1.Scalar datatype:VARCHAR2, CLOB, POSITIVE, DATE, or BOOLEAN 等等
        2.Anchored datatype:使用 %TYPE、%ROWTYPE
        3.Complex datatype:9i R2 開始可以使用 object types and collection types
      index_type 包括:
        INDEX BY BINARY_INTEGER;(9i R2 之前只能使用該類型)
        INDEX BY PLS_INTEGER;
        INDEX BY POSITIVE;
        INDEX BY NATURAL;
        INDEX BY SIGNTYPE;
        INDEX BY VARCHAR2(32767);
        INDEX BY table.column%TYPE;
        INDEX BY cursor.column%TYPE;
        INDEX BY package.variable%TYPE;
        INDEX BY package.subtype;
      
    Declaring a nested table or VARRAY
      CREATE [ OR REPLACE ] TYPE type_name AS | IS
         TABLE OF element_datatype [ NOT NULL ];
      CREATE [ OR REPLACE ] TYPE type_name AS | IS
         VARRAY (max_elements) OF element_datatype [ NOT NULL ];
      DROP TYPE type_name [ FORCE ];
      element_datatype 包括:大部分 scalar datatypes, an object type, or a REF object type,如果是 object type,那麼它的屬性不能是 collection 類型;在 PL/SQL 中,如果是 RECORD,那麼它只能包含 scalars or objects 類型
      FORCE:即使該 collection type 被其它類型引用,也 drop 它
    
    Changing nested table or VARRAY characteristics

      1.改變 VARRAY 元素最大個數:
          ALTER TYPE list_t MODIFY LIMIT 100 INVALIDATE | CASCADE
      2.改變元素類型爲 variable character, RAW, or numeric 的類型長度或精度
          CREATE TYPE list_t AS VARRAY(10) OF VARCHAR2(80);
          ALTER TYPE list_t MODIFY ELEMENT TYPE VARCHAR2(100) INVALIDATE | CASCADE
      INVALIDATE:所有使用該類型的對象失效
      CASCADE:將改變傳遞給所有使用該類型的對象
    
二、Declaring and Initializing Collection Variables

    collection_name collection_type [:= collection_type (...)];
    對於 nested table or VARRAY 需要用構造函數初始化,構造函數可以可以接受用逗號分割的初始值作爲參數,如果不初始化就使用會得到錯誤:ORA-06531: Reference to uninitialized collection
  
    1、Initializing implicitly during direct assignment

      同一 collection type (必須同一個類型,哪怕元素類型相同的不同 collection type 也不行)的不同變量,可以通過直接賦值進行隱式初始化
        DECLARE
           earth_colors Color_tab_t := Color_tab_t('BRICK', 'RUST', 'DIRT');
           wedding_colors Color_tab_t; --必須同一類型,都是 Color_tab_t,這裏沒有初始化
        BEGIN
           wedding_colors := earth_colors; --賦值時同時初始化
           wedding_colors(3) := 'CANVAS';
        END;
      
    2、Initializing implicitly via FETCH

      如果表中的列是 Collection type,那麼可以像一般類型一樣通過 select ... into、FETCH 直接將值傳遞給相同類型的變量,並可以自動給該變量初始化
  
三、Populating Collections with Data

    Using the assignment operator
      1.單個賦值:
          countdown_test_list (43) := 'Internal pressure';
      2.整個 record (結構要一致)賦值:
          DECLARE
             TYPE emp_copy_t IS TABLE OF emp%ROWTYPE;
             l_emps emp_copy_t := emp_copy_t( );
             l_emprec emp%ROWTYPE;
          BEGIN
             l_emprec.ename := 'Steven';
             l_emprec.salary := 10000;
             l_emps.EXTEND
             l_emps (l_emps.LAST) := l_emprec;
          END;
        相同的還可以使用 select ... into、cursor FOR loop、select ... BULK COLLECT into(9i R2 之後,可將整個表賦值給 Collection,不需要初始化) 進行賦值
      3.相同類型的 Collection 直接賦值(不需要初始化)
    
四、Accessing Data Inside a Collection
    需要注意幾點:
      1.對於稀疏 Collection,當訪問不存在的元素時會產生 NO_DATA_FOUND 異常
      2.訪問超出 EXTEND 分配空間的元素時產生 ORA-06533: Subscript beyond count 異常
      3.對於 VARRAY,訪問大於最大元素個數的元素時產生 ORA-06532: Subscript outside of limit 異常
    
五、Collections of Complex Datatypes
    Collections of records
      可以定義元素類型爲 record 的 collection,使用 %ROWTYPE or a programmer-defined record type。適用於 PL/SQL,如果是定義在表的列上,不能使用 %ROWTYPE
    
    Multilevel collections
      9i R2 開始可以定義 collection 的元素類型也爲 collection,既 collection 嵌套,被稱爲 multilevel collections,通過這種方法,可以構造多維 collection。
    
六、Using String-Indexed Collections
    9i R2 開始可以使用 strings 作爲 index type,FIRST, LAST, PRIOR, and NEXT 方法返回的也是 strings
  
七、Working with Collections in SQL
    Oracle8 開始提供 collection pseudo-functions,它們可以使數據表和 collection 的數據互相轉換,只能用於 SQL 語句中
  
    1.The CAST pseudo-function
        在 SQL 中,用於將 built-in datatype or collection type 轉換爲另一種 built-in datatype or collection type
          CREATE TYPE Color_nt AS TABLE OF VARCHAR2(30);
          CREATE TYPE Color_vat AS VARRAY(16) OF VARCHAR2(30);
          CREATE TABLE color_models (
             model_type VARCHAR2(12),
             colors Color_vat);
          SELECT COLUMN_VALUE FROM
             TABLE (SELECT CAST(colors AS Color_nt)
                   FROM color_models
                   WHERE model_type = 'FGB');
                 
    2.The MULTISET pseudo-function
        MULTISET 必須和 CASTs 一起使用,MULTISET 將數據集轉換爲 collection,SQL MULTISET function 和操作 nested tables 的 PL/SQL MULTISET 是完全不同的
          SELECT CAST (MULTISET (SELECT field FROM table) AS collection-type)
          FROM DUAL;
        As with the CAST pseudo-function, MULTISET cannot serve as the target of an INSERT, UPDATE, or DELETE statement.
      
    3.The TABLE pseudo-function
        TABLE 將 collection 轉換爲可以 SELECT from 的結果集,既將 collection 中的內容像數據表一樣 select 出來
        例如,表中含有 collection 字段,現在要找出 collection 中包含某個內容的所有數據:
          SELECT *
            FROM color_models c
           WHERE 'RED' IN
                (SELECT COLUMN_VALUE FROM TABLE(c.colors));
              
          MODEL_TYPE   COLORS
          ------------ ------------------------------------------------------
          RGB          COLOR_TAB_T('RED', 'GREEN', 'BLUE')
        
        COLUMN_VALUE 是 TABLE operator 創建的 system-defined 列名


Nested Table Multiset Operations

10g 之後針對 nested tables 提供了 high-level set operations,將其作爲 multisets 對待

Operation             Return value    Description
=                     BOOLEAN         比較兩個 nested tables,如果 named type、cardinality、elements 相等,返回 TRUE,如果 nested table 中包含 null 則必不相等。10g 之前要比較,只能通過一個個元素來比較
<> or !=              BOOLEAN         比較兩個 nested tables 是否不同
[NOT] IN ( )          BOOLEAN         判斷左邊的 nested table 是否在右邊括號中的 nested tables list 中
x MULTISET EXCEPT     NESTED TABLE    返回一個 NESTED TABLE,它的元素在 x 中,但不在 y 中,所有的 NESTED TABLE 都必須是相同類型的。DISTINCT 表示返回的 nested table 中除去重複元素
    [DISTINCT] y
x MULTISET INTERSECT NESTED TABLE    返回一個 NESTED TABLE,它的元素是 x 和 y 中元素的交集
    [DISTINCT] y
x MULTISET UNION      NESTED TABLE    返回一個 NESTED TABLE,它的元素是 x 和 y 中元素的並集
    [DISTINCT] y
SET(x)                NESTED TABLE    返回一個 NESTED TABLE,包含 x 中不重複的所有元素
x IS [NOT] A SET      BOOLEAN         判斷 x 中的元素是否有重複值
x IS [NOT] EMPTY      BOOLEAN         判斷 x 是否爲空
e [NOT] MEMBER        BOOLEAN         判斷表達式 e 是否包含在 x 的元素中
    [OF] x
y [NOT] SUBMULTISET   BOOLEAN         判斷 y 的元素是否全都包含在 x 的元素中
    [OF] x
  
  
Maintaining Schema-Level Collections

一、Necessary Privileges
    如果創建 Schema-Level 的 nested tables and VARRAYS,其它 Schema 如果需要使用該類型必須有該類型的 EXECUTE 權限:
      GRANT EXECUTE on Color_tab_t TO JOE;
    對於包含 Schema-Level Collections 的 packages, procedures, functions 只要有這些過程的 EXECUTE 權限就可以使用這些類型了,但對於 PL/SQL anonymous blocks 中使用這些類型,只能直接將這些類型的 EXECUTE 權限授予執行的用戶
    如果某表的一列爲 Schema-Level Collection 類型,對該表要有 SELECT, INSERT, UDPATE, and DELETE 權限才能做相應的操作,其次在 INSERT or UPDATE 時還需要有該 Collection 類型的 EXECUTE 權限

二、Collections and the Data Dictionary
    1.USER_TYPES
        所有創建的類型
        SELECT type_name FROM user_types
        WHERE typecode ='COLLECTION';
    2.USER_SOURCE
        類型的定義
        SELECT text FROM user_source
        WHERE name = 'FOO_T' AND type = 'TYPE'
        ORDER BY line;
    3.USER_DEPENDENCIES
        依賴創建的類型的對象
        SELECT name, type FROM user_dependencies
        WHERE referenced_name='FOO_T';
發佈了26 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章