Search code examples
oracleassociative-arraydynamic-sqlexecute-immediateforall

Trying to use a FORALL to insert data dynamically to a table specified to the procedure


I have the need to dynamic know the name of the table that has the same data structure as many others and I can pass in a generic associative array that is of the same structure. Here is the proc

PROCEDURE INSRT_INTER_TBL(P_TABLE_NAME IN VARCHAR2, P_DATA IN tt_type)

IS

BEGIN
    FORALL i IN P_DATA.FIRST .. P_DATA.LAST
        EXECUTE IMMEDIATE
          'INSERT INTO ' || P_TABLE_NAME ||
          ' VALUES  :1'
        USING P_DATA(i);
END INSRT_INTER_TBL;

I am getting the following error

ORA-01006: bind variable does not exist

What am I missing here?

So I had to specify all the columns necessary to insert to the table out in the insert statement like:

PROCEDURE INSRT_INTER_TBL(P_TABLE_NAME IN VARCHAR2, P_DATA IN inter_invc_ln_item_type)

IS

BEGIN
    FORALL i IN P_DATA.FIRST .. P_DATA.LAST
        EXECUTE IMMEDIATE
          'INSERT INTO ' || P_TABLE_NAME || ' (ITEM_PK, pk, units, amt) ' ||
          ' VALUES  (:P_INVC_LN_ITEM_PK, :PK, :UNITS, :AMT)'
        USING IN P_DATA(i).item_pk, P_DATA(i).pk, P_DATA(i).units, P_DATA(i).amt;
END INSRT_INTER_TBL;

Solution

  • The TABLE operator works better than a FORALL here. It uses less code and probably skips some SQL-to-PL/SQL context switches.

    --Simple record and table type.
    create or replace type tt_rec is object
    (
        a number,
        b number
    );
    
    create or replace type tt_type is table of tt_rec;
    
    --Sample schema that will hold results.
    create table test1(a number, b number);
    
    --PL/SQL block that inserts TT_TYPE into a table.
    declare
        p_table_name varchar2(100) := 'test1';
        p_data             tt_type := tt_type(tt_rec(1,1), tt_rec(2,2));
    begin
        execute immediate
        '
            insert into '||p_table_name||'
            select * from table(:p_data)
        '
        using p_data;
        commit;
    end;
    /
    

    You can run the above code in this SQL Fiddle.