Is it possible to run a for each loop on a PL/SQL array?
Asked
Active
Viewed 4.2k times
8
-
Avoid looping constructs in SQL. Start thinking in SET based operations. http://www.simple-talk.com/sql/database-administration/the-road-to-professional-database-development-set-based-thinking/ – Oded Mar 22 '12 at 16:57
-
The Oracle documentation is comprehensive, online and free. You shoudl learn how to use it to answer trivial syntax questions for yourself. Here is the section on PL/SQL loops. http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/controlstructures.htm#i8296 – APC Mar 22 '12 at 17:51
-
Reading the documentaion would also have answered your subsequent question http://stackoverflow.com/q/9827581/146325 too – APC Mar 22 '12 at 17:53
-
3@APC Useless rtfm link. A `for-each` loop iterates over a list of values. The Oracle documentation describes only a basic `for` loop iterating over numbers. – ceving Oct 20 '14 at 16:01
3 Answers
13
for i in my_array.first ..my_array.last loop
--do_something with my_array(i);
end loop;

A.B.Cade
- 16,735
- 1
- 37
- 53
-
1As some comments in ceving's link stated, this would return an error if `my_array` is empty. For that case, it is better to use `FOR i IN 1 .. my_array.COUNT` – plasmaTonic Apr 30 '18 at 10:28
2
It's no possible to iterate over the associative arrays with a non numeric index with a FOR-loop. The solution below works just fine.
-- for-each key in (associative-array) loop ...
declare
type items_type is table of varchar2(32) index by varchar2(32);
items items_type;
begin
items('10') := 'item 10';
items('20') := 'item 20';
items('30') := 'item 30';
dbms_output.put_line('items=' || items.count);
<<for_each>> declare key varchar2(32); begin loop
key := case when key is null then items.first else items.next(key) end;
exit when key is null;
dbms_output.put_line('item(' || key || ')=' || items(key));
--do something with an item
end loop; end for_each;
end;

0xdb
- 3,539
- 1
- 21
- 37
0
In my opinion 0xdb solution is best. Even if you have numeric index it is better to us this construct
DECLARE
TYPE TTab_SomeTable IS TABLE OF VARCHAR2(2000) INDEX BY PLS_INTEGER;
--
vt_SomeTable TTab_SomeTable;
vi_Idx NUMBER;
BEGIN
vt_SomeTable(1) := 'First';
vt_SomeTable(2) := 'Second';
vt_SomeTable(5) := 'Fifth';
vt_SomeTable(10) := 'Tenth';
vi_Idx := vt_SomeTable.FIRST;
LOOP
--
EXIT WHEN vi_Idx IS NULL;
--
dbms_output.Put_Line('vt_SomeTable(' || vi_Idx || ') = ' || vt_SomeTable(vi_Idx));
--
vi_Idx := vt_SomeTable.NEXT(vi_Idx);
--
END LOOP vi_Idx;
END;
It is not susceptible to index discontinuity like below two examples, which will fail on index 3:
DECLARE
TYPE TTab_SomeTable IS TABLE OF VARCHAR2(2000) INDEX BY PLS_INTEGER;
--
vt_SomeTable TTab_SomeTable;
BEGIN
vt_SomeTable(1) := 'First';
vt_SomeTable(2) := 'Second';
vt_SomeTable(5) := 'Fifth';
vt_SomeTable(10) := 'Tenth';
-- Throw No_data_found on vi_Idx = 3
FOR vi_Idx IN vt_SomeTable.FIRST .. vt_SomeTable.LAST
LOOP
dbms_output.Put_Line('vt_SomeTable(' || vi_Idx || ') = ' || vt_SomeTable(vi_Idx));
END LOOP vi_Idx;
END;
DECLARE
TYPE TTab_SomeTable IS TABLE OF VARCHAR2(2000) INDEX BY PLS_INTEGER;
--
vt_SomeTable TTab_SomeTable;
BEGIN
vt_SomeTable(1) := 'First';
vt_SomeTable(2) := 'Second';
vt_SomeTable(5) := 'Fifth';
vt_SomeTable(10) := 'Tenth';
-- Throw No_data_found on vi_Idx = 3.
FOR vi_Idx IN 1 .. vt_SomeTable.COUNT
LOOP
dbms_output.Put_Line('vt_SomeTable(' || vi_Idx || ') = ' || vt_SomeTable(vi_Idx));
END LOOP vi_Idx;
END;

Mateusz Żurek
- 1
- 1