oracle-databasefor-loopplsqlexecute-immediate

Loop over execute immediate


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?


Solution

  • 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
    

    fiddle