I want to loop over a dynamic query that was concatenated before. However, even with this simple example
begin
for rec in (execute immediate 'select dummy from dual') loop
dbms_output.put_line(rec.dummy);
end loop;
end;
I get the error
encountered the symbol immediate when expecting one of the following
How to achieve such a loop?
You can use EXECUTE IMMEDIATE
and BULK COLLECT
the results into a collection variable and then loop through that:
DECLARE
TYPE string_list IS TABLE OF VARCHAR2(1);
v_strings string_list;
BEGIN
EXECUTE IMMEDIATE 'select dummy from dual'
BULK COLLECT INTO v_strings;
FOR i IN 1 .. v_strings.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_strings(i));
END LOOP;
END;
/
Which outputs:
X
If you have multiple columns you can use:
DECLARE
TYPE number_list IS TABLE OF NUMBER;
TYPE string_list IS TABLE OF VARCHAR2(1);
v_numbers number_list;
v_strings string_list;
BEGIN
EXECUTE IMMEDIATE 'select dummy, level from dual connect by level <= 5'
BULK COLLECT INTO v_strings, v_numbers;
FOR i IN 1 .. v_strings.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_strings(i) || ', ' || v_numbers(i));
END LOOP;
END;
/
or you can create an object type:
CREATE TYPE data_obj IS OBJECT( dummy VARCHAR2(1), lvl NUMBER );
and then use:
DECLARE
TYPE data_list IS TABLE OF data_obj;
v_data data_list;
BEGIN
EXECUTE IMMEDIATE 'select data_obj(dummy, level) from dual connect by level <= 5'
BULK COLLECT INTO v_data;
FOR i IN 1 .. v_data.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_data(i).dummy || ', ' || v_data(i).lvl);
END LOOP;
END;
/
Both of which output:
X, 1
X, 2
X, 3
X, 4
X, 5