Skip to Main Content
  • Questions
  • CAST TABLE type not working with EXECUTE IMMEDIATE

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question.

Asked: April 12, 2017 - 9:48 am UTC

Last updated: April 14, 2017 - 10:10 am UTC

Version: 11.2

Viewed 1000+ times

You Asked

Hi,

I have created below TABLE type of VARCHAR2 -
create or replace TYPE VC_ARRAY is table of varchar2(4000);
and tables

create table tb_test_src
as select object_name, object_id from user_objects where rownum <= 20;

create table tb_test_tgt
as select object_name, object_id from user_objects where rownum <= 10;


Please have look at below two procedures,
The only difference is I am executing MERGE command -
1. with EXECUTE IMMEDIATE (p_dummy_with_exe_imm)
2. without EXECUTE IMMEDIATE (p_dummy)

Procedure without EXECUTE IMMEDIATE i.e. p_dummy execute perfectly, but the one with with EXECUTE IMMEDIATE (i.e. p_dummy_with_exe_imm) throwing error as ORA-00904: "TB_ROWID": invalid identifier

Could you please help get rid of this.

CREATE OR REPLACE PROCEDURE p_dummy_with_exe_imm
IS
TYPE r_cursor IS REF CURSOR;
c_cur_var r_cursor;
tb_rowid VC_ARRAY;
n_row_updated pls_integer;
v_sql VARCHAR2(22222);
begin

open c_cur_var for select rowid from tb_test_src;
loop
FETCH c_cur_var BULK COLLECT INTO tb_rowid LIMIT 5;
EXIT WHEN tb_rowid.COUNT = 0;

v_sql := 'MERGE INTO tb_test_tgt tgt
USING ( SELECT * FROM tb_test_src WHERE ROWID IN (select column_value as name from table(cast(tb_rowid as VC_ARRAY)))) src
ON (src.object_name = tgt.object_name)
WHEN MATCHED THEN
UPDATE
SET tgt.object_id = src.object_id
WHEN NOT MATCHED THEN
INSERT (tgt.object_id, tgt.object_name)
VALUES (src.object_id, src.object_name)';

EXECUTE IMMEDIATE v_sql ;
n_row_updated := SQL%ROWCOUNT;
dbms_output.put_line('n_row_updated:'||n_row_updated);
tb_rowid.delete;

end loop;

end p_dummy_with_exe_imm;
/

---------------------------------------------------------------------------------------------------------------------

CREATE OR REPLACE PROCEDURE p_dummy
IS
TYPE r_cursor IS REF CURSOR;
c_cur_var r_cursor;
tb_rowid VC_ARRAY;
n_row_updated pls_integer;
v_sql VARCHAR2(22222);
begin

open c_cur_var for select rowid from tb_test_src;
loop
FETCH c_cur_var BULK COLLECT INTO tb_rowid LIMIT 5;
EXIT WHEN tb_rowid.COUNT = 0;

MERGE INTO tb_test_tgt tgt
USING ( SELECT * FROM tb_test_src WHERE ROWID IN (select column_value as name from table(cast(tb_rowid as VC_ARRAY)))) src
ON (src.object_name = tgt.object_name)
WHEN MATCHED THEN
UPDATE
SET tgt.object_id = src.object_id
WHEN NOT MATCHED THEN
INSERT (tgt.object_id, tgt.object_name)
VALUES (src.object_id, src.object_name);

n_row_updated := SQL%ROWCOUNT;
dbms_output.put_line('n_row_updated:'||n_row_updated);
tb_rowid.delete;

end loop;

end p_dummy;
/



and Connor said...

You simply need to bind the rowid array into the dynamic SQL.


SQL> @drop tb_test_src

Y1                      Y2
----------------------- -------------------------
TABLE                   cascade constraints purge

1 row selected.


Table dropped.

SQL> @drop tb_test_tgt

Y1                      Y2
----------------------- -------------------------
TABLE                   cascade constraints purge

1 row selected.


Table dropped.

SQL>
SQL>
SQL> create or replace TYPE VC_ARRAY is table of varchar2(4000);
  2  /

Type created.

SQL>
SQL> create table tb_test_src
  2  as select object_name, object_id from user_objects where rownum <= 20;

Table created.

SQL>
SQL> create table tb_test_tgt
  2  as select object_name, object_id from user_objects where rownum <= 10;

Table created.

SQL>
SQL> CREATE OR REPLACE PROCEDURE p_dummy_with_exe_imm
  2  IS
  3  TYPE r_cursor IS REF CURSOR;
  4  c_cur_var r_cursor;
  5  tb_rowid VC_ARRAY;
  6  n_row_updated pls_integer;
  7  v_sql VARCHAR2(22222);
  8  begin
  9  open c_cur_var for select rowid from tb_test_src;
 10  loop
 11  FETCH c_cur_var BULK COLLECT INTO tb_rowid LIMIT 5;
 12  EXIT WHEN tb_rowid.COUNT = 0;
 13  v_sql :=
 14  'MERGE INTO tb_test_tgt tgt
 15  USING ( SELECT * FROM tb_test_src WHERE ROWID IN (select column_value as name from table(cast(tb_rowid as VC_ARRAY)))) src
 16  ON (src.object_name = tgt.object_name)
 17  WHEN MATCHED THEN
 18  UPDATE
 19  SET tgt.object_id = src.object_id
 20  WHEN NOT MATCHED THEN
 21  INSERT (tgt.object_id, tgt.object_name)
 22  VALUES (src.object_id, src.object_name)';
 23
 24  EXECUTE IMMEDIATE v_sql ;
 25  n_row_updated := SQL%ROWCOUNT;
 26  dbms_output.put_line('n_row_updated:'||n_row_updated);
 27  tb_rowid.delete;
 28  end loop;
 29  end p_dummy_with_exe_imm;
 30  /

Procedure created.

SQL>
SQL>
SQL> CREATE OR REPLACE PROCEDURE p_dummy
  2  IS
  3  TYPE r_cursor IS REF CURSOR;
  4  c_cur_var r_cursor;
  5  tb_rowid VC_ARRAY;
  6  n_row_updated pls_integer;
  7  v_sql VARCHAR2(22222);
  8  begin
  9
 10  open c_cur_var for select rowid from tb_test_src;
 11  loop
 12  FETCH c_cur_var BULK COLLECT INTO tb_rowid LIMIT 5;
 13  EXIT WHEN tb_rowid.COUNT = 0;
 14
 15  MERGE INTO tb_test_tgt tgt
 16  USING ( SELECT * FROM tb_test_src WHERE ROWID IN (select column_value as name from table(cast(tb_rowid as VC_ARRAY)))) src
 17  ON (src.object_name = tgt.object_name)
 18  WHEN MATCHED THEN
 19  UPDATE
 20  SET tgt.object_id = src.object_id
 21  WHEN NOT MATCHED THEN
 22  INSERT (tgt.object_id, tgt.object_name)
 23  VALUES (src.object_id, src.object_name);
 24
 25  n_row_updated := SQL%ROWCOUNT;
 26  dbms_output.put_line('n_row_updated:'||n_row_updated);
 27  tb_rowid.delete;
 28
 29  end loop;
 30  end p_dummy;
 31  /

Procedure created.

SQL>
SQL> exec p_dummy

PL/SQL procedure successfully completed.

SQL>
SQL> exec p_dummy_with_exe_imm
BEGIN p_dummy_with_exe_imm; END;

*
ERROR at line 1:
ORA-00904: "TB_ROWID": invalid identifier
ORA-06512: at "MCDONAC.P_DUMMY_WITH_EXE_IMM", line 24
ORA-06512: at line 1


SQL>
SQL>
SQL> CREATE OR REPLACE PROCEDURE p_dummy_with_exe_imm
  2  IS
  3  TYPE r_cursor IS REF CURSOR;
  4  c_cur_var r_cursor;
  5  tb_rowid VC_ARRAY;
  6  n_row_updated pls_integer;
  7  v_sql VARCHAR2(22222);
  8  begin
  9  open c_cur_var for select rowid from tb_test_src;
 10  loop
 11  FETCH c_cur_var BULK COLLECT INTO tb_rowid LIMIT 5;
 12  EXIT WHEN tb_rowid.COUNT = 0;
 13  v_sql :=
 14  'MERGE INTO tb_test_tgt tgt
 15  USING ( SELECT * FROM tb_test_src WHERE ROWID IN (select column_value as name from table(cast(:tb_rowid as VC_ARRAY)))) src
 16  ON (src.object_name = tgt.object_name)
 17  WHEN MATCHED THEN
 18  UPDATE
 19  SET tgt.object_id = src.object_id
 20  WHEN NOT MATCHED THEN
 21  INSERT (tgt.object_id, tgt.object_name)
 22  VALUES (src.object_id, src.object_name)';
 23
 24  EXECUTE IMMEDIATE v_sql using tb_rowid;
 25  n_row_updated := SQL%ROWCOUNT;
 26  dbms_output.put_line('n_row_updated:'||n_row_updated);
 27  tb_rowid.delete;
 28  end loop;
 29  end p_dummy_with_exe_imm;
 30  /

Procedure created.

SQL>
SQL> exec p_dummy_with_exe_imm

PL/SQL procedure successfully completed.

SQL>



Is this answer out of date? If it is, please let us know via a Comment

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library