Oracle PL/SQL Tutorial/Collections/Varray

Материал из SQL эксперт
Перейти к: навигация, поиск

Содержание

A procedure that uses EXISTS and LAST

   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> CREATE OR REPLACE PROCEDURE vs3 (sub integer)

 2  IS
 3  CURSOR vcur IS
 4    SELECT name, members FROM club;
 5  x varchar2(30);
 6  BEGIN
 7    FOR j IN vcur LOOP
 8      x := j.name||" No Members";
 9      IF j.members.exists(1) THEN -- exists
10          IF sub <= j.members.last THEN -- last
11            x := j.name||" "||j.members(sub);
12              -- access array element
13          ELSE
14            x := j.name||" Less than "||sub||" members";
15          END IF;
16      END IF;
17      dbms_output.put_line(x);
18    END LOOP;
19  END vs3;
20  /

Procedure created. SQL> SQL> exec vs3(1); AL Brenda FL Gen PL/SQL procedure successfully completed. SQL> exec vs3(2); AL Richard FL John PL/SQL procedure successfully completed. SQL> exec vs3(3); AL Less than 3 members FL Steph PL/SQL procedure successfully completed. SQL> exec vs3(4); AL Less than 4 members FL JJ PL/SQL procedure successfully completed. SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL></source>


Assign value to VARRAY

   <source lang="sql">

SQL> SET ECHO ON SQL> SET SERVEROUTPUT ON SQL> SQL> DECLARE

 2      TYPE emp_array IS VARRAY(100) OF VARCHAR2(30);
 3
 4      emps emp_array;
 5      inx1 PLS_INTEGER;
 6
 7  BEGIN
 8      emps := emp_array ("emp One","emp Two");
 9
10      FOR inx1 IN 1..2 LOOP
11          DBMS_OUTPUT.PUT_LINE(emps(inx1));
12      END LOOP;
13  END;
14  /

emp One emp Two PL/SQL procedure successfully completed. SQL> SQL></source>


Column_value is a built-in function/pseudo-variable that is held over from the DBMS_SQL package

   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> SQL> SQL> SELECT c.name, p.column_value, COUNT(p.column_value)

 2  FROM club c, TABLE(c.members) p
 3  -- WHERE c.name = "AL"
 4  GROUP by c.name, p.column_value
 5

SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL></source>


CREATE TABLE with a VARRAY

   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

SQL> SQL> DESC club;

Name                                                                                                                                                                  Null?    Type
-----------
NAME                                                                                                                                                                           VARCHAR2(10)
ADDRESS                                                                                                                                                                        VARCHAR2(20)
CITY                                                                                                                                                                           VARCHAR2(20)
PHONE                                                                                                                                                                          VARCHAR2(8)
MEMBERS                                                                                                                                                                        MEM_TYPE

SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


Creating a Varray Type

  1. A varray stores an ordered set of elements.
  2. Each element has an index associated with it.
  3. A varray has a maximum size that you can change dynamically.

You create a varray type using the SQL DDL CREATE TYPE statement.

You specify the maximum size and the type of elements stored in the varray when creating the

The basic Oracle syntax for the CREATE TYPE statement for a VARRAY type definition would be:



   <source lang="sql">

CREATE OR REPLACE TYPE name-of-type IS VARRAY(nn)of type</source>


Decreasing the Size of an Array

You cannot delete an element inside the array.

Even if you set it to NULL, it still exists.

The only thing you can do is decrease the size of the array.



   <source lang="sql">

SQL> SQL> declare

 2      type month_va is varray(13) of VARCHAR2(20);
 3      v_month_va month_va:=month_va();
 4      v_count_nr number;
 5  begin
 6      v_month_va.extend(3);
 7      v_month_va(1):="January";
 8      v_month_va(2):="February";
 9      v_month_va(3):="March";
10
11      v_month_va(2):=null;
12      if v_month_va.exists(2)
13      then
14         DBMS_OUTPUT.put_line("Object Exists");
15      end if;
16
17      v_month_va(3):=v_month_va(2);
18      v_month_va.trim(1);
19      DBMS_OUTPUT.put_line("Count:"||v_month_va.count);
20      DBMS_OUTPUT.put_line("Last:"||v_month_va.last);
21  end;
22  /

Object Exists Count:2 Last:2 PL/SQL procedure successfully completed. SQL> SQL></source>


Defining our type to be a VARRAY with 10 elements, where each element is a varying character string of up to 15 characters.

   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

SQL> SQL> drop type mem_type;</source>


EXISTS and LAST

Suppose we add a row with no members to the Club table:

EXISTS returns a Boolean that acknowledges the presence (T) or absence (F) of a member of a VARRAY.



   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> INSERT INTO club values ("NY","55 Fifth Ave.","NYC",

 2    "999-9999",null)
 3  SELECT *
 4  FROM club
 5

SQL> SQL> CREATE OR REPLACE FUNCTION vs (vlist club.members%type, sub integer)

 2  RETURN VARCHAR2
 3  IS
 4  BEGIN
 5    IF vlist.exists(1) THEN
 6     IF sub <= vlist.last THEN
 7       RETURN vlist(sub);
 8     ELSE
 9       RETURN "Less than "||sub||" members";
10     END IF;
11    ELSE
12     RETURN "No members";
13    END IF;
14  END vs;
15  /

Function created. SQL> ---The EXISTS function requires an argument to tell which element of the VARRAY is referred to. In the above function we are saying in the coded if-statement that if there is no first element, then return "No members." If a first member of the array is present, then the array is not null and we can look for whichever member is sought (per the value of sub). If the value of sub is less than the value of the last subscript, then the return of ""Less than "||sub||" members"" is effected. SQL> SQL> SELECT c.name, vs(members,3) member_name

 2  FROM club c;

NAME


MEMBER_NAME


AL Less than 3 members FL Steph

SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped.</source>


Extracting individual members of a VARRAY may be accomplished using two other functions: THE and VALUE

   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> SELECT VALUE(x) FROM

 2  THE(SELECT c.members FROM club c
 3  WHERE c.name = "FL") x
 4  WHERE VALUE(x) is not null;

VALUE(X)


Gen John Steph JJ SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


Getting Information on Varrays

You can use the DESCRIBE command to get information on your varray types.



   <source lang="sql">

SQL> CREATE or replace TYPE addressVarray AS VARRAY(2) OF VARCHAR2(50);

 2  /

Type created. SQL> SQL> DESCRIBE addressVarray;

addressVarray VARRAY(2) OF VARCHAR2(50)

SQL></source>


If aliases are used, they must be used consistently

   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> SQL> SELECT c.name "Clubname"

 2  FROM club c
 3  WHERE "Gen" IN
 4  (SELECT * FROM TABLE(c.members));

Clubname


FL SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


Inside the loop, you are accessing array elements by their subscripts.

   <source lang="sql">

SQL> SQL> declare

 2      type month_va is varray(13) of VARCHAR2(20);
 3      v_month_va month_va;
 4      v_count_nr number;
 5  begin
 6      v_month_va:=month_va("A","B","C","D","E","F","G");
 7      DBMS_OUTPUT.put_line("Length:"||v_month_va.count);
 8
 9      for i in v_month_va.first..v_month_va.last
10      loop
11          DBMS_OUTPUT.put_line("v_month_va(i): "||v_month_va(i));
12      end loop;
13  end;
14  /

Length:7 v_month_va(i): A v_month_va(i): B v_month_va(i): C v_month_va(i): D v_month_va(i): E v_month_va(i): F v_month_va(i): G PL/SQL procedure successfully completed.</source>


LAST and COUNT give the same result for VARRAYs.

The functions FIRST and LAST may be used to set the upper and lower limit of a for-loop to access members of the array one at a time in PL/SQL.



   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> CREATE OR REPLACE PROCEDURE vartest1 IS

 2  CURSOR fcur IS SELECT name, members FROM club;
 3  BEGIN
 4    FOR j IN fcur LOOP
 5      dbms_output.put_line("For the "||j.name||" club ...");
 6        IF j.members.exists(1) THEN
 7          FOR k IN j.members.first..j.members.last LOOP
 8            dbms_output.put_line("**   "||j.members(k));
 9          END LOOP;
10        ELSE
11          dbms_output.put_line("**   There are no members on file");
12        END IF;
13      END LOOP;   /* end for j in fcur loop */
14  END vartest1;
15  /

Procedure created. SQL> exec vartest1; For the AL club ...

    • Brenda
    • Richard

For the FL club ...

    • Gen
    • John
    • Steph
    • JJ

PL/SQL procedure successfully completed. SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL> SQL></source>


Loading a Table with a VARRAY in It: INSERT VALUEs with Constants

Oracle"s VARRAYs behave like classes in object-oriented programming. Classes are instantiated into objects using constructors.



   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SELECT *

 2  FROM club;

NAME ADDRESS CITY PHONE


-------------------------------------------------- -------------------- --------

MEMBERS


AL 111 First St. Mobile 222-2222 MEM_TYPE("Brenda", "Richard") FL 222 Second St. Orlando 333-3333 MEM_TYPE("Gen", "John", "Steph", "JJ")

SQL> SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


Loop through by using the built-in NEXT, PRIOR.

If there are no more elements, the built-in method will return NULL.



   <source lang="sql">

SQL> SQL> declare

 2      type month_va is varray(13) of VARCHAR2(20);
 3      v_month_va month_va;
 4      v_count_nr number;
 5  begin
 6      v_month_va:=month_va("A","B","C","D","E","F","G");
 7      DBMS_OUTPUT.put_line("Length:"||v_month_va.count);
 8
 9      for i in v_month_va.first..v_month_va.last
10      loop
11          DBMS_OUTPUT.put_line("v_month_va(i): "||v_month_va(i));
12      end loop;
13  end;
14  /

Length:7 v_month_va(i): A v_month_va(i): B v_month_va(i): C v_month_va(i): D v_month_va(i): E v_month_va(i): F v_month_va(i): G PL/SQL procedure successfully completed.</source>


Manipulating the VARRAY with The TABLE Function

The TABLE function can be used to indirectly access data in the VARRAY by using an IN predicate:



   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SELECT name "Clubname"

 2  FROM club
 3  WHERE "Gen" IN
 4  (SELECT * FROM TABLE(club.members))
 5

SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


Manipulating the VARRAY with The VARRAY Self-join

A statement can be created that joins the values of the virtual table (created with the TABLE function) to the rest of the values in the table



   <source lang="sql">

SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> SQL> SELECT c.name, c.address, p.column_value

 2  FROM club c, TABLE(c.members) p;

NAME ADDRESS COLUMN_VALUE


-------------------------------------------------- ---------------

AL 111 First St. Brenda AL 111 First St. Richard FL 222 Second St. Gen FL 222 Second St. John FL 222 Second St. Steph FL 222 Second St. JJ 6 rows selected. SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


One way to make the "members" behave like an array is first to include the row number in the result set like this:

   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SELECT n, val

 2  FROM
 3  (SELECT rownum n, COLUMN_VALUE val FROM
 4  THE(SELECT c.members FROM club c
 5  WHERE c.name = "FL") x
 6  WHERE COLUMN_VALUE IS NOT NULL);
        N VAL

---------------
        1 Gen
        2 John
        3 Steph
        4 JJ

SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL></source>


Query table with VARRAY type column by column name

   <source lang="sql">

SQL> SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SELECT name, city, members

 2  FROM club
 3

SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL></source>


Query VARRAY column

   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SELECT *

 2  FROM club;

NAME ADDRESS CITY PHONE


-------------------------------------------------- -------------------- --------

MEMBERS


AL 111 First St. Mobile 222-2222 MEM_TYPE("Brenda", "Richard") FL 222 Second St. Orlando 333-3333 MEM_TYPE("Gen", "John", "Steph", "JJ")

SQL> SQL> SQL> SQL> drop table club; Table dropped. SQL> drop TYPE mem_type; Type dropped. SQL></source>


The CAST function converts an object type (such as a VARRAY) into a common type that can be queried. Oracle 10g automatically converts the VARRAY without the CAST.

The CAST function may also be used with the MULTISET function to perform DML operations on VARRAYs. MULTISET is the "reverse" of CAST in that MULTISET converts a nonobject set of data to an object set. Suppose we create a new table of names:



   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> SQL> SELECT COLUMN_VALUE FROM

 2  THE(SELECT CAST(c.members as mem_type)
 3  FROM club c
 4  WHERE c.name = "FL");

COLUMN_VALUE


Gen John Steph JJ SQL> SQL> SQL> SQL> CREATE TABLE newnames (n varchar2(20))

 2  /

Table created. SQL> INSERT INTO newnames VALUES ("Beryl")

 2  /

1 row created. SQL> INSERT INTO newnames VALUES ("Fred")

 2  /

1 row created. SQL> SELECT *

 2  FROM newnames
 3  /

N


Beryl Fred SQL> SQL> INSERT INTO club VALUES ("VA",null,null,null,null)

 2  /

1 row created. SQL> UPDATE club SET members =

 2  CAST(MULTISET(SELECT n FROM newnames) as mem_type)
 3  WHERE name = "VA"
 4  /

1 row updated. SQL> SQL> select * from club; NAME ADDRESS CITY PHONE


-------------------------------------------------- -------------------- --------

MEMBERS


AL 111 First St. Mobile 222-2222 MEM_TYPE("Brenda", "Richard") FL 222 Second St. Orlando 333-3333 MEM_TYPE("Gen", "John", "Steph", "JJ") VA MEM_TYPE("Beryl", "Fred")

SQL> SQL> INSERT INTO club VALUES("MD",null, null,null,

 2  CAST(MULTISET(SELECT * FROM newnames) as mem_type))
 3  /

1 row created. SQL> SQL> select * from club; NAME ADDRESS CITY PHONE


-------------------------------------------------- -------------------- --------

MEMBERS


AL 111 First St. Mobile 222-2222 MEM_TYPE("Brenda", "Richard") FL 222 Second St. Orlando 333-3333 MEM_TYPE("Gen", "John", "Steph", "JJ") VA MEM_TYPE("Beryl", "Fred") MD MEM_TYPE("Beryl", "Fred")

SQL> SQL> SQL> drop table newnames; Table dropped. SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped.</source>


The COUNT Function

The COUNT function returns the number of members in a VARRAY.



   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> CREATE OR REPLACE PROCEDURE vartest IS

 2  CURSOR fcur IS
 3    SELECT city, members FROM club;
 4  BEGIN
 5    FOR j IN fcur LOOP
 6       IF j.members.exists(1) THEN
 7         dbms_output.put_line(j.City||" has "|| j.members.count||" members");
 8
 9         END IF;
10      END LOOP;   /* end for j in fcur loop */
11  END vartest;
12  /

Procedure created. SQL> exec vartest; Mobile has 2 members Orlando has 4 members PL/SQL procedure successfully completed. SQL> SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL></source>


Then, the individual array element can be extracted with a WHERE filter:

   <source lang="sql">

SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> SQL> SELECT n, val

 2  FROM
 3  (SELECT rownum n, COLUMN_VALUE val FROM
 4  THE(SELECT c.members FROM club c
 5  WHERE c.name = "FL") x
 6  WHERE COLUMN_VALUE IS NOT NULL)
 7  WHERE n=3;
        N VAL

---------------
        3 Steph

SQL> SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL> SQL></source>


The subscript of the last element is always equal to the size of the array.

   <source lang="sql">

SQL> SQL> declare

 2      type month_va is varray(13) of VARCHAR2(20);
 3      v_month_va month_va;
 4      v_count_nr number;
 5  begin
 6      v_month_va:=month_va("A","B","C","D","E","F","G");
 7      DBMS_OUTPUT.put_line("Length:"||v_month_va.count);
 8
 9      for i in v_month_va.first..v_month_va.last
10      loop
11          DBMS_OUTPUT.put_line("v_month_va(i): "||v_month_va(i));
12      end loop;
13  end;
14  /

Length:7 v_month_va(i): A v_month_va(i): B v_month_va(i): C v_month_va(i): D v_month_va(i): E v_month_va(i): F v_month_va(i): G PL/SQL procedure successfully completed.</source>


Using PL/SQL to Create Functions to Access Elements

   <source lang="sql">

SQL> SQL> SQL> SQL> CREATE OR REPLACE TYPE mem_type IS VARRAY(10) of VARCHAR2(15)

 2  /

Type created. SQL> SQL> SQL> CREATE TABLE club (Name VARCHAR2(10),

 2  Address VARCHAR2(20),
 3  City VARCHAR2(20),
 4  Phone VARCHAR2(8),
 5  Members mem_type)
 6  /

Table created. SQL> SQL> SQL> SQL> INSERT INTO club VALUES ("AL","111 First St.","Mobile",

 2  "222-2222", mem_type("Brenda","Richard"));

1 row created. SQL> SQL> INSERT INTO club VALUES ("FL","222 Second St.","Orlando",

 2  "333-3333", mem_type("Gen","John","Steph","JJ"));

1 row created. SQL> SQL> SQL> CREATE OR REPLACE FUNCTION vs (vlist club.members%type, sub integer)

 2  RETURN VARCHAR2
 3  IS
 4  BEGIN
 5    IF sub <= vlist.last THEN
 6      RETURN vlist(sub);
 7    END IF;
 8      RETURN NULL;
 9  END vs;
10  /

Function created. SQL> SQL> SELECT vs(members,2)

 2  FROM club
 3  /

VS(MEMBERS,2)


Richard John SQL> SELECT DECODE(vs(members,3),null,"No members",vs(members,3))

 2  FROM club
 3  WHERE name IN ("FL", "MD")
 4  /

DECODE(VS(MEMBERS,3),NULL,"NOMEMBERS",VS(MEMBERS,3))


Steph SQL> SQL> SQL> drop table club; Table dropped. SQL> drop type mem_type; Type dropped. SQL></source>


Using VARRAYs

In the Oracle environment, array subscripts start from 1, and not from 0 (as in C and Java).

VARRAYs are of fixed length.

You specify the length of the array when you define it.

Arrays of elements of the same type use sequential numbers as a subscript.

VARRAYS can be used both in PL/SQL and SQL.

You should use VARRAYs when you know the size of your data set and that size is very stable.



   <source lang="sql">

declare

 type VarrayType is varray(size) of ElementType;

... create or replace type VarrayType is varray(size) of ElementType;</source>


VARRAY in action

   <source lang="sql">

SQL> -- create demo table SQL> create table Employee(

 2    ID                 VARCHAR2(4 BYTE)         NOT NULL,
 3    First_Name         VARCHAR2(10 BYTE),
 4    Last_Name          VARCHAR2(10 BYTE),
 5    Start_Date         DATE,
 6    End_Date           DATE,
 7    Salary             Number(8,2),
 8    City               VARCHAR2(10 BYTE),
 9    Description        VARCHAR2(15 BYTE)
10  )
11  /

Table created. SQL> SQL> -- prepare data SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2               values ("01","Jason",    "Martin",  to_date("19960725","YYYYMMDD"), to_date("20060725","YYYYMMDD"), 1234.56, "Toronto",  "Programmer")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("02","Alison",   "Mathews", to_date("19760321","YYYYMMDD"), to_date("19860221","YYYYMMDD"), 6661.78, "Vancouver","Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("03","James",    "Smith",   to_date("19781212","YYYYMMDD"), to_date("19900315","YYYYMMDD"), 6544.78, "Vancouver","Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("04","Celia",    "Rice",    to_date("19821024","YYYYMMDD"), to_date("19990421","YYYYMMDD"), 2344.78, "Vancouver","Manager")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("05","Robert",   "Black",   to_date("19840115","YYYYMMDD"), to_date("19980808","YYYYMMDD"), 2334.78, "Vancouver","Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("06","Linda",    "Green",   to_date("19870730","YYYYMMDD"), to_date("19960104","YYYYMMDD"), 4322.78,"New York",  "Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("07","David",    "Larry",   to_date("19901231","YYYYMMDD"), to_date("19980212","YYYYMMDD"), 7897.78,"New York",  "Manager")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("08","James",    "Cat",     to_date("19960917","YYYYMMDD"), to_date("20020415","YYYYMMDD"), 1232.78,"Vancouver", "Tester")
 3  /

1 row created. SQL> SQL> SQL> SQL> -- display data in the table SQL> select * from Employee

 2  /

ID FIRST_NAME LAST_NAME START_DAT END_DATE SALARY CITY DESCRIPTION


-------------------- -------------------- --------- --------- ---------- ---------- ---------------

01 Jason Martin 25-JUL-96 25-JUL-06 1234.56 Toronto Programmer 02 Alison Mathews 21-MAR-76 21-FEB-86 6661.78 Vancouver Tester 03 James Smith 12-DEC-78 15-MAR-90 6544.78 Vancouver Tester 04 Celia Rice 24-OCT-82 21-APR-99 2344.78 Vancouver Manager 05 Robert Black 15-JAN-84 08-AUG-98 2334.78 Vancouver Tester 06 Linda Green 30-JUL-87 04-JAN-96 4322.78 New York Tester 07 David Larry 31-DEC-90 12-FEB-98 7897.78 New York Manager 08 James Cat 17-SEP-96 15-APR-02 1232.78 Vancouver Tester 8 rows selected. SQL> SQL> SQL> SQL> declare

 2      type month_va is varray(13) of VARCHAR2(20);
 3      v_month_va month_va;
 4      v_count_nr number;
 5  begin
 6      v_month_va:=month_va("January","February","March","April","May","June","July","August","September","October","November","December");
 7      DBMS_OUTPUT.put_line("Length:"||v_month_va.count);
 8
 9      v_month_va.extend;
10      v_month_va(v_month_va.last):="Null";
11      DBMS_OUTPUT.put_line("Length:"||v_month_va.count);
12
13      for i in v_month_va.first..v_month_va.last
14      loop
15          select count(*) into v_count_nr from employee
16          where nvl(replace(to_char(start_date,"Month")," "), "Null")=v_month_va(i);
17
18          DBMS_OUTPUT.put_line(v_month_va(i)||": "||v_count_nr);
19      end loop;
20  end;
21  /

Length:12 Length:13 January: 1 February: 0 March: 1 April: 0 May: 0 June: 0 July: 2 August: 0 September: 1 October: 1 November: 0 December: 2 Null: 0 PL/SQL procedure successfully completed. SQL> SQL> SQL> SQL> -- clean the table SQL> drop table Employee

 2  /

Table dropped.</source>


VARRAY of Cursor

   <source lang="sql">

SQL> -- create demo table SQL> create table Employee(

 2    ID                 VARCHAR2(4 BYTE)         NOT NULL,
 3    First_Name         VARCHAR2(10 BYTE),
 4    Last_Name          VARCHAR2(10 BYTE),
 5    Start_Date         DATE,
 6    End_Date           DATE,
 7    Salary             Number(8,2),
 8    City               VARCHAR2(10 BYTE),
 9    Description        VARCHAR2(15 BYTE)
10  )
11  /

Table created. SQL> SQL> -- prepare data SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2               values ("01","Jason",    "Martin",  to_date("19960725","YYYYMMDD"), to_date("20060725","YYYYMMDD"), 1234.56, "Toronto",  "Programmer")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("02","Alison",   "Mathews", to_date("19760321","YYYYMMDD"), to_date("19860221","YYYYMMDD"), 6661.78, "Vancouver","Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("03","James",    "Smith",   to_date("19781212","YYYYMMDD"), to_date("19900315","YYYYMMDD"), 6544.78, "Vancouver","Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("04","Celia",    "Rice",    to_date("19821024","YYYYMMDD"), to_date("19990421","YYYYMMDD"), 2344.78, "Vancouver","Manager")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("05","Robert",   "Black",   to_date("19840115","YYYYMMDD"), to_date("19980808","YYYYMMDD"), 2334.78, "Vancouver","Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("06","Linda",    "Green",   to_date("19870730","YYYYMMDD"), to_date("19960104","YYYYMMDD"), 4322.78,"New York",  "Tester")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("07","David",    "Larry",   to_date("19901231","YYYYMMDD"), to_date("19980212","YYYYMMDD"), 7897.78,"New York",  "Manager")
 3  /

1 row created. SQL> insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)

 2                values("08","James",    "Cat",     to_date("19960917","YYYYMMDD"), to_date("20020415","YYYYMMDD"), 1232.78,"Vancouver", "Tester")
 3  /

1 row created. SQL> SQL> SQL> SQL> -- display data in the table SQL> select * from Employee

 2  /

ID FIRST_NAME LAST_NAME START_DAT END_DATE SALARY CITY DESCRIPTION


---------- ---------- --------- --------- ---------- ---------- ---------------

01 Jason Martin 25-JUL-96 25-JUL-06 1234.56 Toronto Programmer 02 Alison Mathews 21-MAR-76 21-FEB-86 6661.78 Vancouver Tester 03 James Smith 12-DEC-78 15-MAR-90 6544.78 Vancouver Tester 04 Celia Rice 24-OCT-82 21-APR-99 2344.78 Vancouver Manager 05 Robert Black 15-JAN-84 08-AUG-98 2334.78 Vancouver Tester 06 Linda Green 30-JUL-87 04-JAN-96 4322.78 New York Tester 07 David Larry 31-DEC-90 12-FEB-98 7897.78 New York Manager 08 James Cat 17-SEP-96 15-APR-02 1232.78 Vancouver Tester 8 rows selected. SQL> SQL> SET ECHO ON SQL> SET SERVEROUTPUT ON SQL> SQL> DECLARE

 2      CURSOR all_emps IS
 3          SELECT *
 4          FROM employee
 5          ORDER BY first_name;
 6
 7      TYPE emp_array IS VARRAY(100) OF employee%ROWTYPE;
 8
 9      emps emp_array;
10      inx1 PLS_INTEGER;
11      inx2 PLS_INTEGER;
12  BEGIN
13      inx1 := 0;
14
15      emps := emp_array ();
16
17      FOR emp IN all_emps LOOP
18          inx1 := inx1 + 1;
19          emps.extend();
20          emps(inx1).id := emp.id;
21          emps(inx1).first_name := emp.first_name;
22          emps(inx1).salary := emp.salary;
23      END LOOP;
24
25      FOR inx2 IN 1..emps.count LOOP
26          DBMS_OUTPUT.PUT_LINE (emps(inx2).id ||" " || emps(inx2).first_name);
27      END LOOP;
28  END;
29  /

02 Alison 04 Celia 07 David 03 James 08 James 01 Jason 06 Linda 05 Robert PL/SQL procedure successfully completed. SQL> SQL> SQL> SQL> SQL> -- clean the table SQL> drop table Employee

 2  /

Table dropped. SQL> SQL></source>