PL/SQL COLLECTION TYPE

·        Index-by tables or Associative array
·        Nested table
·        Variable-size array or Varray

 
PL/SQL provides three collection types:

·        Index-by tables or Associative array

·        Nested table

·        Variable-size array or Varray

Index-By Tables:

The first type of collection is known as index-by tables. These behave in the same way as arrays except that have no upper bounds, allowing them to constantly extend. As the name implies, the collection is indexed using BINARY_INTEGER values, which do not need to be consecutive. The collection is extended by assigning values to an element using an index value that does not currently exist.

This can only be used in PL/SQL

Nested Table Collections:

Nested table collections are an extension of the index-by tables. The main difference between the two is that nested tables can be stored in a database column but index-by tables cannot. In addition some DML operations are possible on nested tables when they are stored in the database. During creation the collection must be dense, having consecutive subscripts for the elements. Once created elements can be deleted using the DELETE method to make the collection sparse. The NEXT method overcomes the problems of traversing sparse collections.

Varray Collections:


A VARRAY is similar to a nested table except you must specifiy an upper bound in the declaration. Like nested tables they can be stored in the database, but unlike nested tables individual elements cannot be deleted so they remain dense.

Index-by tables or Associative array

Nested Table Collections:


Example 1 :








Insert data into table:

INSERT INTO nested_table VALUES (1, my_tab_dev('A'));
INSERT INTO nested_table VALUES (2, my_tab_dev('B', 'C'));
INSERT INTO nested_table VALUES (3, my_tab_dev('D', 'E', 'F'));
COMMIT;

Select data from nested_table:
 SELECT * FROM nested_table;  -- using F9
ID COL1
--------------------
1          (DATASET)
2          (DATASET)
3          (DATASET)

COL1 DATA is displayed as (DATASET) this will not be displayed as this is nested table
SELECT * FROM nested_table;  -- using F5 ( Will not display in grid form)
ID COL1(ELEMENT)                                     
-- ---------------------------------------------------
 1 MY_TAB_DEV(A)                                     
 2 MY_TAB_DEV(B,C)                                   
 3 MY_TAB_DEV(D,E,F)                                  
3 rows selected.
How to display complete data in grid form (UNNESTING the table )
SELECT id, COLUMN_VALUE FROM nested_table t1, TABLE(t1.col1) t2;
        ID COLUMN_VALUE
---------- ------------------------
         1 A
         2 B
         2 C
         3 D
         3 E
         3 F
6 rows selected.
--Extract data with PL/SQL:

declare
  v_vcarray my_tab_dev;
begin
  for c1 in (select * from nested_table) loop
      dbms_output.put_line('Row fetched...');
      FOR i IN c1.col1.FIRST..c1.col1.LAST LOOP
          dbms_output.put_line('...property fetched: '|| c1.col1(i));
      END LOOP;
  end loop;
end;
/

/* OUTPUT */
Row fetched...
...property fetched: A
Row fetched...
...property fetched: B
...property fetched: C
Row fetched...
...property fetched: D
...property fetched: E
...property fetched: F


Example 2 : Complex one







INSERT INTO customers VALUES (1,
            address_tab(
              address_t('101 First', 'Redwood Shores', 'CA', '94065'),
              address_t('123 Maple', 'Mill Valley',    'CA', '90952')
            )                );

INSERT INTO customers VALUES (2,
            address_tab(
              address_t('124 dev', 'hinjewadi',    'MH', '41057')
                          ));

select * from customers;  -- using F9
CUSTID
ADDRESS
1
(DATASET)
2
(DATASET)

This will not give the out as the whole object as DATASET for Address field.
select * from customers;  -- using F5
CUSTID
----------
ADDRESS(STREET,CITY,STATE,ZIP)                                                 
-----------------------------------------------------------------------------
         1
ADDRESS_TAB(ADDRESS_T(101 First,Redwood Shores,CA,94065),ADDRESS_T(123 Maple,Mil
l Valley,CA,90952))                                                            
                                                                               
         2
ADDRESS_TAB(ADDRESS_T(124 dev,hinjewadi,MH,41057))                                     
2 rows selected.

This will give the output in text form will not be in form of grid

SELECT CUSTID , STREET,CITY,   STATE,  ZIP
FROM customers2 C1, TABLE (C1.ADDRESS)

CUSTID  STREET   CITY   STATE  ZIP   
-------------------------------------
101         123   SHAH1 GJ    45446
101         101   DEV 1 MH    94065
102         124   HINJ  MH    4474
Detailed Output as its stored in DB
CUSTID
ADDRESS
101
STREET  
CITY  
STATE
ZIP
123
SHAH1
GJ
45446
101
DEV
MH
94065
102
STREET  
CITY  
STATE
ZIP
124
HINJ
MH
4474

There are two rows in address nested table while only single value for  CUSTID =”101”
 O/P will have CUSTID “101” will be cross join between CUSTID and ADDRESS
SCALAR COLLECITON
Scalar variable is any datatype that holds one thing at a time
Scalar collection returns with a “COLUMN_VALUE” column name, this can be used in output. Multi-dimensional or aggregate table return with an explicitly described record type information is converted In database for VARRAY and Nested table.  Similarly this is not true for PL/SQL record type you need to convert using pipelined table.
VARRAY
You can use VARRAY in SQL as well as PL/SQL , can be used in  anonymous  as well as named block at schema level.
--USING  VARRAY IN ANNONYMOUS BLOCK

DECLARE
    varr1 SCALAR_VARRAY := SCALAR_VARRAY('ONE','TWO','THREE');
    varr2 SCALAR_VARRAY := SCALAR_VARRAY();
BEGIN
    FOR I IN 1..varr1.COUNT LOOP
        varr2.EXTEND ;      -- Allocated space to the colleciton
        varr2(I):=varr1(I); -- assign a value
    END LOOP;
   
    FOR I IN 1..varr2.count LOOP
        dbms_output.put_line('varr2 :(' || i ||') : ' || varr2(I));
    END LOOP;
   
END;

OUTPUT
varr2 :(1) : ONE
varr2 :(2) : TWO
varr2 :(3) : THREE
-- DROPPING CREATED TYPE
DROP TYPE SCALAR_VARRAY;
-- USING VARRAY IN NAMED BLOCK
CREATE OR REPLACE FUNCTION GET_ARRAY(VAL1 VARCHAR2,VAL2 VARCHAR2,VAL3 VARCHAR2)
        RETURN SCALAR_VARRAY  IS
    varr3 SCALAR_VARRAY := scalar_varray();
    i NUMBER(2):=0;
 BEGIN
    IF VAL1 IS NOT NULL THEN
        varr3.extend;
         i := i+1;
         varr3(i):=VAL1;
    end if ;
   
    IF VAL2 IS NOT NULL THEN
        varr3.extend;
         i := i+1;
         varr3(i):=VAL2;
    end if ;
   
    IF VAL3 IS NOT NULL THEN
        varr3.extend;
         i := i+1;
         varr3(i):=VAL3;
    end if ;
 
    IF i =0  THEN
        varr3(1):='NO VALUE PASSED';
    end if;
   
    return varr3;
   
 END;
 /

select * from table(GET_ARRAY(1,2,3));
-- OUTPUT
COLUMN_VALUE
------------
1
2
3

select * from table(GET_ARRAY(NULL,NULL,5));

-- OUTPUT
COLUMN_VALUE
------------
5 

Few methods for VARRAY
·         COUNT / LAST – this gives maximum index of the array
·         LIMIT – Returns maximum number ( this only works with VARRAY)



INDEX-BY TABLE: ASSOCIATIVE ARRAY 

An index-by table (also called an associative array) is a set of key-value pairs. Each key is unique and is used to locate the corresponding value. The key can be either an integer or a string.

An index-by table is created using the following syntax. Here, we are creating an index-by table named table_name whose keys will be of subscript_type and associated values will be of element_type



DECLARE
   TYPE salary IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
   salary_list salary;
   name   VARCHAR2(20);
BEGIN
   -- adding elements to the table
   salary_list('dev')  := 62000;
   salary_list('shah')  := 75000;
   salary_list('d1') := 10v0000;
   salary_list('d2') := 78000;

   -- printing the table
   name := salary_list.FIRST;
   WHILE name IS NOT null LOOP
      dbms_output.put_line
      ('Salary of ' || name || ' is ' || TO_CHAR(salary_list(name)));
      name := salary_list.NEXT(name);
   END LOOP;
END;
/
--When the above code is executed at SQL prompt, it produces the following result:
-------------- OUTPUT-------------------------
Salary of dev is 62000
Salary of shah is 75000
Salary of d1 is 100000
Salary of d2 is 78000
-------------- OUTPUT-------------------------

PL/SQL procedure successfully completed.
Example:
Elements of an index-by table could also be a %ROWTYPE of any database table or %TYPE of any database table field. The following example illustrates the concept. We will use the CUSTOMERS table stored in our database as:
Select * from customers;

+----+----------+-----+-----------+------------------------------+
| ID | NAME       | AGE | ADDRESS                   | SALARY   |
+----+----------+-----+-----------+-------------------------------+
|  1 | Dev        |  32 | Ahmedabad                    |  2000.00 |
|  2 | Shah       |  25 | Delhi                       |  1500.00 |
|  3 | devshah    |  23 | Kota                        |  2000.00 |
+----+----------+-----+-----------+------------------------------+

DECLARE
   CURSOR c_customers is
      select  name from customers;
 
   TYPE c_list IS TABLE of customers.name%type INDEX BY binary_integer;
   name_list c_list;
   counter integer :=0;
BEGIN
   FOR n IN c_customers LOOP
      counter := counter +1;
      name_list(counter)  := n.name;
      dbms_output.put_line('Customer('||counter|| '):'||name_list(counter));
  END LOOP;
END;
/
--When the above code is executed at SQL prompt, it produces the following result:
-------------- OUTPUT-------------------------
Customer(1): Dev
Customer(2): Shah
Customer(3): devshah   
-------------- OUTPUT-------------------------


ollection TypeNumber of ElementsSubscript TypeDense or SparseWhere CreatedCan Be Object Type Attribute
Associative array (or index-by table)UnboundedString or integerEitherOnly in PL/SQL blockNo
Nested tableUnboundedIntegerStarts dense, can become sparseEither in PL/SQL block or at schema levelYes
Variable-size array (Varray)BoundedIntegerAlways denseEither in PL/SQL block or at schema levelYes



No comments:

Post a Comment