Collection ها که در ارواکل plsql استفاده می شود مانند استفاده از آرایه ها در دیکر زبان های برنامه نویسی می باشد. اوراکل 3 نوع collection دارد که هر کدوم روش ها و خواص متفاوت دارند.

Index by tables و یا آرایه های انجمنی :

اولین نوع از collection ها index by tables می باشد. رفتاری مانند آرایه ها دارند البته بدون محدودیت در سقف که به آنها اجازه رشد دائمی می دهد. همانطور که از اسم آنها مشخص است، از BINARY_INTEGER برای شاخص گذاری استفاده می شود که نیازی به پشت سر هم بودن ندارند.این نوع collection ها به تخصیص مقدار شاخص یکتا گسترش می یابد.

SET SERVEROUTPUT ON SIZE 1000000

DECLARE

TYPE table_type IS TABLE OF NUMBER(10)

INDEX BY BINARY_INTEGER;

v_tab table_type;

v_idx NUMBER;

BEGIN

— Initialise the collection.

<< load_loop >>

FOR i IN 1 .. 5 LOOP

v_tab(i) := i;

END LOOP load_loop;

— Delete the third item of the collection.

v_tab.DELETE(3);

— Traverse sparse collection

v_idx := v_tab.FIRST;

<< display_loop >>

WHILE v_idx IS NOT NULL LOOP

DBMS_OUTPUT.PUT_LINE(‘The number ‘ || v_tab(v_idx));

v_idx := v_tab.NEXT(v_idx);

END LOOP display_loop;

END;

/

The number 1

The number 2

The number 4

The number 5

PL/SQL procedure successfully completed.

SQL>

Nested Table Collections
این نوع collection ها مدل توسعه یافته ای از index by tables می باشد. فرق اساسی بین این دو، nested table ها می توانند در ستون های پایگاه داده ذخیره شوند و در زمانی که در پایگاه داده ذخیره شده باشند دستورات DML را می توان بر روی آنها اجرا کرد. وقتی عنصری ایجاد شود، با دستور DELETE می توان آن را حذف کرد و مجموعه پراکنده ای را ایجاد کرد. البته با متد NEXT
می توان عنصر بعد را پیدا کرد و از فضا های خالی ایجاد شده گذر کرد.

SET SERVEROUTPUT ON SIZE 1000000

DECLARE

TYPE table_type IS TABLE OF NUMBER(10);

v_tab table_type;

v_idx NUMBER;

BEGIN

— Initialise the collection with two values.

v_tab := table_type(1, 2);

— Extend the collection with extra values.

<< load_loop >>

FOR i IN 3 .. 5 LOOP

v_tab.extend;

v_tab(v_tab.last) := i;

END LOOP load_loop;

— Delete the third item of the collection.

v_tab.DELETE(3);

— Traverse sparse collection

v_idx := v_tab.FIRST;

<< display_loop >>

WHILE v_idx IS NOT NULL LOOP

DBMS_OUTPUT.PUT_LINE(‘The number ‘ || v_tab(v_idx));

v_idx := v_tab.NEXT(v_idx);

END LOOP display_loop;

END;

/

The number 1

The number 2

The number 4

The number 5

PL/SQL procedure successfully completed.

SQL>

Varray Collections
این نوع از collection ها، مشابه nested table ها می باشند با این فرق در این مدل حد بالا را در هنگام تعریف مشخص می کنیم و در این مدل نمی توان از دستور DELETE برای حذف عنصری استفاده کرد.

SET SERVEROUTPUT ON SIZE 1000000

DECLARE

TYPE table_type IS VARRAY(5) OF NUMBER(10);

v_tab table_type;

v_idx NUMBER;

BEGIN

— Initialise the collection with two values.

v_tab := table_type(1, 2);

— Extend the collection with extra values.

<< load_loop >>

FOR i IN 3 .. 5 LOOP

v_tab.extend;

v_tab(v_tab.last) := i;

END LOOP load_loop;

— Can’t delete from a VARRAY.

— v_tab.DELETE(3);

— Traverse collection

v_idx := v_tab.FIRST;

<< display_loop >>

WHILE v_idx IS NOT NULL LOOP

DBMS_OUTPUT.PUT_LINE(‘The number ‘ || v_tab(v_idx));

v_idx := v_tab.NEXT(v_idx);

END LOOP display_loop;

END;

/

The number 1

The number 2

The number 3

The number 4

The number 5

PL/SQL procedure successfully completed.

SQL>

در صورتی که برای تعریف عنصر جدید، از محدودیت حد بالا عیور کنیم با خطای زیر مواجه خواهیم شد.

DECLARE

*

ERROR at line 1:

ORA-06532: Subscript outside of limit

ORA-06512: at line 12

Assignments and Equality Tests
Assignments فقط بین محموعه هایی از یک نوع امکان پذیر می باشد.
به مثال زیر توجه کنید.

DECLARE

TYPE table_type IS TABLE OF NUMBER(10);

v_tab_1 table_type;

v_tab_2 table_type;

BEGIN

— Initialise the collection with two values.

v_tab_1 := table_type(1, 2);

— Assignment works.

v_tab_2 := v_tab_1;

END;

/

PL/SQL procedure successfully completed.

SQL>

در مثال عملیات فوق را با دو TYPE متفاوت انجام میدهیم و نتیجه را مشاهده می کنیم.

DECLARE

TYPE table_type_1 IS TABLE OF NUMBER(10);

TYPE table_type_2 IS TABLE OF NUMBER(10);

v_tab_1 table_type_1;

v_tab_2 table_type_2;

BEGIN

— Initialise the collection with two values.

v_tab_1 := table_type_1(1, 2);

— Assignment causes compilation error.

v_tab_2 := v_tab_1;

END;

/

v_tab_2 := v_tab_1;

*

ERROR at line 11:

ORA-06550: line 11, column 14:

PLS-00382: expression is of wrong type

ORA-06550: line 11, column 3:

PL/SQL: Statement ignored

SQL>

برای آزمون برابری در collection ها به مثال زیر توجه بفرمایید.

SET SERVEROUTPUT ON

DECLARE

TYPE table_type IS TABLE OF NUMBER(10);

v_tab_1 table_type;

v_tab_2 table_type;

BEGIN

— Initialise the collection with two values.

v_tab_1 := table_type(1, 2);

v_tab_2 := v_tab_1;

IF v_tab_1 = v_tab_2 THEN

DBMS_OUTPUT.put_line(‘1: v_tab_1 = v_tab_2’);

END IF;

v_tab_1 := table_type(1, 2, 3);

IF v_tab_1 != v_tab_2 THEN

DBMS_OUTPUT.put_line(‘2: v_tab_1 != v_tab_2’);

END IF;

END;

/

1: v_tab_1 = v_tab_2

2: v_tab_1 != v_tab_2

PL/SQL procedure successfully completed.

SQL>

متد های مربوط به collection ها :
متد های متعددی برای collection ها موجود می باشد اما برخی از این متد ها قابل استفاده برای هر 3 نوع collection نمی باشد.

EXISTS(n) – Returns TRUE if the specified element exists.

COUNT – Returns the number of elements in the collection.

LIMIT – Returns the maximum number of elements for a VARRAY, or NULL for nested tables.

FIRST – Returns the index of the first element in the collection.

LAST – Returns the index of the last element in the collection.

PRIOR(n) – Returns the index of the element prior to the specified element.

NEXT(n) – Returns the index of the next element after the specified element.

EXTEND – Appends a single null element to the collection.

EXTEND(n) – Appends n null elements to the collection.

EXTEND(n1,n2) – Appends n1 copies of the n2th element to the collection.

TRIM – Removes a single element from the end of the collection.

TRIM(n) – Removes n elements from the end of the collection.

DELETE – Removes all elements from the collection.

DELETE(n) – Removes element n from the collection.

DELETE(n1,n2) – Removes all elements from n1 to n2 from the collection.

عملیات های مجموعه ای در Collection ها :
MULTISET UNION {ALL | DISTINCT} Operator
برای اجتماع دو collection از دستور MULTISET UNION استفاده می کنیم . این دستور با UNION ALL یکسان می شود.

SET SERVEROUTPUT ON

DECLARE

TYPE t_tab IS TABLE OF NUMBER;

l_tab1 t_tab := t_tab(1,2,3,4,5,6);

l_tab2 t_tab := t_tab(5,6,7,8,9,10);

BEGIN

l_tab1 := l_tab1 MULTISET UNION l_tab2;

FOR i IN l_tab1.first .. l_tab1.last LOOP

DBMS_OUTPUT.put_line(l_tab1(i));

END LOOP;

END;

/

1

2

3

4

5

6

5

6

7

8

9

10

PL/SQL procedure successfully completed.

SQL>

یا دستور UNION DISTINCT مقادیر تکراری در اجتماع حذف می گردند.

SET SERVEROUTPUT ON

DECLARE

TYPE t_tab IS TABLE OF NUMBER;

l_tab1 t_tab := t_tab(1,2,3,4,5,6);

l_tab2 t_tab := t_tab(5,6,7,8,9,10);

BEGIN

l_tab1 := l_tab1 MULTISET UNION DISTINCT l_tab2;

FOR i IN l_tab1.first .. l_tab1.last LOOP

DBMS_OUTPUT.put_line(l_tab1(i));

END LOOP;

END;

/

1

2

3

4

5

6

7

8

9

10

PL/SQL procedure successfully completed.

SQL>

MULTISET EXCEPT {DISTINCT} Operator
برای بدست آوردن اختلاف دو nest table استفاده می گردد.

SET SERVEROUTPUT ON

DECLARE

TYPE t_tab IS TABLE OF NUMBER;

l_tab1 t_tab := t_tab(1,2,3,4,5,6,7,8,9,10);

l_tab2 t_tab := t_tab(6,7,8,9,10);

BEGIN

l_tab1 := l_tab1 MULTISET EXCEPT l_tab2;

FOR i IN l_tab1.first .. l_tab1.last LOOP

DBMS_OUTPUT.put_line(l_tab1(i));

END LOOP;

END;

/

1

2

3

4

5

PL/SQL procedure successfully completed.

SQL>

MULTISET INTERSECT {DISTINCT} Operator
برای بدست آوردن اشنراک ها استفاده می گردد.

SET SERVEROUTPUT ON

DECLARE

TYPE t_tab IS TABLE OF NUMBER;

l_tab1 t_tab := t_tab(1,2,3,4,5,6,7,8,9,10);

l_tab2 t_tab := t_tab(6,7,8,9,10);

BEGIN

l_tab1 := l_tab1 MULTISET INTERSECT l_tab2;

FOR i IN l_tab1.first .. l_tab1.last LOOP

DBMS_OUTPUT.put_line(l_tab1(i));

END LOOP;

END;

/

6

7

8

9

10

PL/SQL procedure successfully completed.

SQL>

Multidimensional Collections
Collection ها می توانند از روی recordtypes ها و یا از collection ها ساخته شوند.

SET SERVEROUTPUT ON

— Collection of records.

DECLARE

TYPE t_row IS RECORD (

id NUMBER,

description VARCHAR2(50)

);

TYPE t_tab IS TABLE OF t_row;

l_tab t_tab := t_tab();

BEGIN

FOR i IN 1 .. 10 LOOP

l_tab.extend();

l_tab(l_tab.last).id := i;

l_tab(l_tab.last).description := ‘Description for ‘ || i;

END LOOP;

END;

/

— Collection of records based on ROWTYPE.

CREATE TABLE t1 (

id NUMBER,

description VARCHAR2(50)

);

SET SERVEROUTPUT ON

DECLARE

TYPE t_tab IS TABLE OF t1%ROWTYPE;

l_tab t_tab := t_tab();

BEGIN

FOR i IN 1 .. 10 LOOP

l_tab.extend();

l_tab(l_tab.last).id := i;

l_tab(l_tab.last).description := ‘Description for ‘ || i;

END LOOP;

END;

/

DECLARE

TYPE t_tab1 IS TABLE OF NUMBER;

TYPE t_tab2 IS TABLE OF t_tab1;

l_tab1 t_tab1 := t_tab1(1,2,3,4,5);

l_tab2 t_tab2 := t_tab2();

BEGIN

FOR i IN 1 .. 10 LOOP

l_tab2.extend();

l_tab2(l_tab2.last) := l_tab1;

END LOOP;

END;

/