type table_type_name is table of element_type index by binary_integer;In the following example we define two table types (one table will contain integer elements and the other will contain the same type of elements as field login of the table Student) and declare two variables of the types
declare type TDataTable is table of number index by binary_integer; type TLoginTable is table of Student.login%type index by binary_integer; v_Login TLoginTable; v_data TDataTable; begin ...When a type and a variable of the type are declared, we can refer to any particular element of the table by its index putting it in parenthesis after the variable name, for example to refer to the 3-rd element of the v_Login table we need to write
v_Login(3)Thus, we can assign some elements of the table by doing this:
v_data(3) := 123; v_data(6) := 17; v_data(-2) := 10;By running this code we defined three elements of the table. That means that the table v_data contains only three elements with indices -2, 3, and 6. If now we try to read from any elements with an index other than these three the no_data_found exception will be generated.
These are the several things we need to know about index-by tables:
The general syntax for creating a nested table is
type table_type_name is table of table_type [not null];The table_type cannot be boolean, nchar, nclob, nvarchar2, or ref cursor.
One more difference between index-by and nested tables is initialization. While an index-by table can be created but empty (no elements), a nested table needs to be initialized. If it's not initialized in the declaration section, it will be automatically initialized by NULL and any attempt to add an element to it will raise "ORA-6531: COLLECTION_IS_NULL" exception. To initialize a nested table we need to use a constructor. The constructor for a nested table has the same name as the table type itself. The arguments of the constructor become elements of the table (with sequential indexes starting with 1). The following example show how to declared a nested table and initialize it
declare type TDataTable is table of number; -- create a table with 5 elements v_data1 TDataTable := TDataTable(1, 23, 456, 7, 9); -- create a table with one element v_data2 TDataTable := TDataTable(23); -- create an empty table v_data3 TDataTable := TDataTable(); ...Once a table is created we can increase the number of elements it can hold by using extend method.
| Method | Return type | Description | Valid for |
|---|---|---|---|
| exists | boolean | Returns true if the specified element exists in the collection | all |
| count | number | Returns the number of elements in the collection | all |
| limit | number | Returns the max number of elements in the collection | nested tables (always returns null), varrays |
| first | binary_integer | returns the index of the first element in the collection | all |
| last | binary_integer | returns the index of the last element in the collection | all |
| next | binary_integer | returns the index of the next element, relative to the the given element, in the collection | all |
| prior | binary_integer | returns the index of the prior element, relative to the the given element, in the collection | all |
| extend | n/a | adds elements to the collection | nested tables, varrays |
| trim | n/a | removes elements from the end of the collection | nested tables, varrays |
| delete | n/a | removes specified element from the collection | index-by tables, nested tables |
declare
type TName is table of pl_test.name%type;
v_name TName := TName();
type TID is table of pl_test.id%type;
v_id TID := TID();
begin
v_name.extend(100);
v_id.extend(100);
select name, id
bulk collect into v_name, v_id
from pl_test;
dbms_output.put_line('retrieved ' || v_name.count || ' elements' );
for c in 1..v_name.count loop
dbms_output.put_line(v_name(c) || ' ' || v_id(c));
end loop;
end;
In the returning into clause the bulk collect can be used to retrieve information about all changes (deletes) made to a table. The following example shows how to do that:
declare
type TName is table of pl_test.name%type;
v_name TName := TName();
begin
v_name.extend(100);
update pl_test
set id = id-1
returning name bulk collect into v_name;
dbms_output.put_line('retrieved ' || v_name.count || ' elements' );
for c in 1..v_name.count loop
dbms_output.put_line(v_name(c));
end loop;
end;
forall ind in 1..v_name.count insert into pl_test values (v_name(ind), v_id(ind));Similarly we can pass a collection to the delete or update statement. The following example shows how to use that statement to send either a whole collection or a part of a collection to the SQL engine:
declare
type TName is table of pl_test.name%type;
v_name TName := TName();
type TID is table of pl_test.id%type;
v_id TID := TID();
begin
v_name.extend(100);
v_id.extend(100);
-- retrieve all IDs from the table
select id
bulk collect into v_id
from pl_test;
dbms_output.put_line('Table has ' || v_id.count || ' elements' );
-- delete all but one rows from the table
forall ind in 1..v_id.count-1
delete from pl_test
where id = v_id(ind)
returning name bulk collect into v_name;
dbms_output.put_line(v_name.count || ' elements deleted' );
-- insert these elements back
forall ind in 1..v_name.count
insert into pl_test values (v_name(ind), v_id(ind));
dbms_output.put_line(v_name.count || ' elements inserted' );
-- print the whole table back
select name, id
bulk collect into v_name, v_id
from pl_test;
dbms_output.put_line('retrieved ' || v_name.count || ' elements' );
for c in 1..v_name.count loop
dbms_output.put_line(v_name(c) || ' ' || v_id(c));
end loop;
end;