Skip to Main Content
  • Questions
  • Saveing the Output from a Dynamic SQL

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Omar.

Asked: June 30, 2002 - 1:03 am UTC

Last updated: March 03, 2004 - 6:01 pm UTC

Version: 8.1.7

Viewed 1000+ times

You Asked

Hi Tom,
I am trying to get a set of result from a Dynamic SQL but I have a problem, What I am doing is

SQL> CREATE OR REPLACE procedure get_subfactor_values2 (acc_cat_code varchar2,
2 P_CURRENCY varchar2,p_policy_no varchar2 ,result out number,v_sub_val_array out EG_ACC_NB_CALL2.sub_val_tbl)
3 is
4 tbl varchar2(10);
5 str varchar2(5000);
6 into_str varchar2(120);
7 rows_processed integer;
8 source_cursor integer;
9 begin
10
11 RESULT := 0;
12 tbl := acc_cat_code||'_EXT';
13 dbms_output.put_line('Table Name is '||tbl);
14 str := 'SELECT B.SUBFACTOR_1_VAL,B.SUBFACTOR_2_VAL,B.SUBFACTOR_3_VAL,B.SUBFACTOR_4_VA
15 '
16 ||' INTO '||v_sub_val_array(1)||','||v_sub_val_array(2)||','||v_sub_val_array(3)||','
l_array(4)||'
17 '
18 ||' FROM ACC_POSTINGS A,AC_INTERNAL_ACCOUNTS B,
19 '
20 ||tbl||' WHERE A.BATCH_ID = '||tbl||'.BATCH_ID'||' AND A.EVENT_NO =
21 '
22 ||tbl||'.EVENT_NO
23 '
24 ||'AND A.POSTING_NO= '||TBL||'.POSTING_NO
25 '
26 ||'AND A.INTERNAL_ACCOUNT_ID = B.INTERNAL_ACCOUNT_ID
27 '
28 ||'AND A.POSTING_SWF = '||''''||P_CURRENCY||'''
29 '
30 ||'AND '||TBL||'.POLICY_NO = '||''''||P_POLICY_NO||'''
31 '
32 ||';'
33 ||'end;'
34 ;
35 dbms_output.put_line(v_sub_val_array(1));
36 dbms_output.put_line(v_sub_val_array(2));
37 dbms_output.put_line(v_sub_val_array(3));
38 dbms_output.put_line(v_sub_val_array(4));
39 source_cursor := dbms_sql.open_cursor;
40 dbms_sql.parse(source_cursor,str,dbms_sql.NATIVE );
41 rows_processed := dbms_sql.execute(source_cursor);
42 dbms_sql.close_cursor(source_cursor);
43 exception
44 when others then
45 result := 1;
46 if dbms_sql.is_open(source_cursor) then
47 dbms_sql.close_cursor(source_cursor);
48 end if;
49 raise;
50
51 end;
52 /

Procedure created.

SQL> SQL> set serveroutput on;

SQL> declare
2 RESULT NUMBER;
3 v_sub_val_array EG_ACC_NB_CALL2.sub_val_tbl;
4 begin
5 get_subfactor_values2 ('ADP','EGP','06500003601' ,result ,v_sub_val_array);
6 dbms_output.put_line(result);
7 end;
8 /
Table Name is ADP_EXT
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "CUSTOMER.GET_SUBFACTOR_VALUES2", line 49
ORA-06512: at line 5

As you see the table name is correct but always give me an errors,
I do not know where is the error? Is it wrong to try to get an output from a Dynamic SQL ?, How to get the same result using NATIVE SQL?,
Thank you in advance Tom.

and Tom said...

You do not use INTO in dynamic sql -- only in static SQL. The error is coming from line 35 really -- when you try to access the array (and it has NO DATA)

Here is the proper way to code this:

CREATE OR REPLACE procedure
get_subfactor_values2 (acc_cat_code varchar2,
P_CURRENCY varchar2,
p_policy_no varchar2 ,
result out number,
v_sub_val_array out EG_ACC_NB_CALL2.sub_val_tbl )
is
begin
result := 0;
execute immediate
'SELECT B.SUBFACTOR_1_VAL,
B.SUBFACTOR_2_VAL,
B.SUBFACTOR_3_VAL,
B.SUBFACTOR_4_VAL
FROM ACC_POSTINGS A,AC_INTERNAL_ACCOUNTS B, ' || acc_cat_code || '_EXT c
WHERE A.BATCH_ID = C.BATCH_ID
AND A.EVENT_NO = C.EVENT_NO
AND A.POSTING_NO= C.POSTING_NO
AND A.INTERNAL_ACCOUNT_ID = B.INTERNAL_ACCOUNT_ID
AND A.POSTING_SWF = :currency
AND C.POLICY_NO = :policy_no'
into v_sub_val_array(1), v_sub_val_array(2),
v_sub_val_array(3), v_sub_val_array(4)
using p_currency, p_policy_no;
exception
when no_data_found then
result := 1;
raise;
end;
/

Remember -- BIND VARIABLES -- use them!!! Very very important (you should have been using them with dbms_sql.bind_variable above!!)

But, you never use INTO inside of a dynamic SQL select like that. Using DBMS_SQL, you would have had to:

0) open
1) parse & define
2) BIND!!!!
3) execute
4) fetch -- make sure you got one
5) use dbms_sql.column_value 4 times to retrieve the 4 columns
6) fetch again -- make sure you DON'T get one
7) close

NDS (native dynamic sql) makes this a tad easier, so that is what I did.



Rating

  (8 ratings)

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

Comments

Ridiculous

Reader, June 30, 2002 - 11:35 pm UTC

I don't understand why people never study and they just simply post the question without undertstanding what is happening and why is it happening.....Sorry Tom...i just could not control after reading the question...

Very useful new rule about INTO reserved word !

Omar Foda, July 01, 2002 - 4:38 am UTC

Thank u Tom for your kind answer,
It is the first time I know that I can not use INTO within the Dynamic SQL, I will try your code and I hope it will work,
Thanks and best regards.


No data found using arrays with dbms_sql

A reader, March 26, 2003 - 5:43 pm UTC

Hi Tom,

I am using dbms_sql to bin some variables because I don't know how many variables I will need in the "in" list until I run the program.
I am using arrays in order to return the result and be able to manipulate the data, but the procedures are reaching the error "no data found" when I tried to retrieve the data.
Can you help to figure out what the problem is with these procedures.
Here you have the code:

create or replace procedure built_query_ret_result (p_colnames in array,p_operator in array, p_values in array,
p_values_operin in array,p_selqntcol in number, p_query in varchar2, 
l_ret_accid_tab out dbms_sql.Number_Table,l_ret_ordid_tab out  dbms_sql.Number_Table,
l_ret_ordstat_tab out dbms_sql.Number_Table,l_ret_orditid_tab out dbms_sql.Number_Table,
l_ret_shipid_tab out  dbms_sql.Number_Table ) as
--
l_cursor int default dbms_sql.open_cursor;
l_query           long;
l_cond_oper       varchar2(20) default ' ';
l_comma           varchar2(1)  default '';
l_status          int;
l_columvalue      varchar2(4000);
l_in_flag         varchar2(1) default 'N';
l_nullval_flag    varchar2(1) default 'N';
l_accid_tab       dbms_sql.Number_Table;
l_ordid_tab       dbms_sql.Number_Table;
l_ordstat_tab     dbms_sql.Number_Table;
l_orditid_tab     dbms_sql.Number_Table;
l_shipid_tab      dbms_sql.Number_Table;
l_indx number := 10;
begin
 if p_values is null then
  l_nullval_flag:='Y';
 end if;
 if p_values_operin is not null then
  l_in_flag:='Y';
 end if;
 l_query:=p_query;
 for i in 1 ..p_colnames.count loop
  if upper(p_operator(i))='IN' then
     l_query:=l_query||l_cond_oper||p_colnames(i)||' '||p_operator(i)||' ( ';
     for x in 1 ..p_values_operin.count loop
      l_query:=l_query||l_comma||':bin_inval'||x;
      if x=1 then
        l_comma:=',';
      end if;
     end loop;
     l_query:=l_query||' ) ';
  else
    l_query:=l_query||l_cond_oper||p_colnames(i)||' '||p_operator(i)||' '||':bin_var'||i;
  end if;
  l_cond_oper:=' and ';
 end loop;
 dbms_sql.parse(l_cursor, l_query,dbms_sql.native);
 if l_nullval_flag='N' then
   for i in 1..p_values.count loop
     dbms_sql.bind_variable(l_cursor,':bin_var'||i, p_values(i));
   end loop;
 end if;
 if l_in_flag='Y' then
    for i in 1..p_values_operin.count loop
     dbms_sql.bind_variable(l_cursor,':bin_inval'||i, p_values_operin(i));
    end loop;
 end if;
--
dbms_sql.define_array(l_cursor,1,l_ret_accid_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,2,l_ret_ordid_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,3,l_ret_ordstat_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,4,l_ret_orditid_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,5,l_ret_shipid_tab,p_selqntcol,l_indx);
--
 l_status:=dbms_sql.execute(l_cursor);
 while (dbms_sql.fetch_rows(l_cursor)>0)
   loop
      dbms_sql.column_value(l_cursor,1,l_ret_accid_tab);
      dbms_sql.column_value(l_cursor,2,l_ret_ordid_tab);
      dbms_sql.column_value(l_cursor,3,l_ret_ordstat_tab);
      dbms_sql.column_value(l_cursor,4,l_ret_orditid_tab);
      dbms_sql.column_value(l_cursor,5,l_ret_shipid_tab);
   end loop;
 for i in 1 .. l_ret_ordid_tab.count loop
  dbms_output.put_line(to_char(l_ret_accid_tab(i))||to_char(l_ret_ordid_tab(i))||to_char(l_ret_orditid_tab(i))||
                       to_char(l_ret_ordstat_tab(i))||to_char(l_ret_shipid_tab(i)));
 end loop;
   dbms_Sql.close_Cursor(l_cursor);
end;
/

Procedure created.

Procedure #2
------------
create or replace procedure show_result is
v_cursor types.rc;
v_ord_id number default 3007;
v_colnames array      :=array('a.order_id','b.order_item_id');
v_operator array      :=array('=','in');
v_values array        :=array(v_ord_id);
v_values_operin array :=array();
v_query varchar2(4000);
l_ret_accid_tab   dbms_sql.Number_Table;
l_ret_ordid_tab   dbms_sql.Number_Table;
l_ret_ordstat_tab dbms_sql.Number_Table;
l_ret_orditid_tab dbms_sql.Number_Table;
l_ret_shipid_tab  dbms_sql.Number_Table;
v_strsql varchar2(4000);
v_pos number default 0;
i number;
rowquery ssw.order_items%rowtype;
begin
 v_query:='select a.account_id,a.order_id,a.order_status,b.order_item_id,b.SHIP_ID '||
          'from ssw.orders a , ssw.order_items b '||
          'where b.order_id=a.order_id and';
 i:=1;
 select count(*) into v_pos from ssw.order_items where order_id=v_ord_id;
 v_values_operin.extend(v_pos);
 v_strsql:='select * from ssw.order_items where order_id=:xord_id';
 open v_cursor for v_strsql using v_ord_id;
 loop 
    fetch v_cursor into rowquery;
    exit when v_cursor%notFound;
    v_values_operin(i):=rowquery.order_item_id;
    i:=i+1;
 end loop;
 built_query_ret_result(v_colnames,v_operator,v_values,v_values_operin,v_pos,v_query,l_ret_accid_tab,l_ret_ordid_tab,l_ret_ordstat_tab,l_ret_orditid_tab,l_ret_shipid_tab);
 dbms_output.put_line('l_ret_ordid_tab.count='||to_char(l_ret_ordid_tab.count));
 for i in 1 .. l_ret_ordid_tab.count loop
  dbms_output.put_line(to_char(l_ret_accid_tab(i))||to_char(l_ret_ordid_tab(i))||to_char(l_ret_orditid_tab(i))||
                       to_char(l_ret_ordstat_tab(i))||to_char(l_ret_shipid_tab(i)));
 end loop;
end;
/

Procedure created.

Error I receive when I try to run the procedures.
-----------------------------------------------------
SQL>set serveroutput on
SQL>exec show_result;
BEGIN show_result; END;

*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "CTW.BUILT_QUERY_RET_RESULT", line 72
ORA-06512: at "CTW.SHOW_RESULT", line 33
ORA-06512: at line 1

Do you know why the dbms_sql.column_value is not loaded the data into the arrays? What am i doing wrong here?
I can't not figure out where the problem is.

Thanks for any help you can give me. 

Tom Kyte
March 26, 2003 - 6:53 pm UTC

unfortunately -- you give me only code -- not a test case.

I'm not a compiler (some people disagree with me on that but thats another story)

Tell you what -- when I'm taking questions, feel free to post an entire working test case with create tables, et. al. Something anyone could take and run in their database.




No data found using arrays with dbms_sql (cont.)

A reader, March 26, 2003 - 8:03 pm UTC

Tom,
Sorry about the test case.
My database is an Enterprise edition release 8.1.7.3.0 on a Sun solaris sever.

Thanks for any help you can give me on this.

Here you have all you need in order to reproduce my test case.

prompt Here you have a test case......Thanks......
prompt There some parameters that you have to add like: default tablespace, temporary tables..
prompt and it will ask you the users names (ctw and ssw) in order to assing quota on the tablespace...
prompt ....

conn system

create user ctw identified by ctw
default tablespace &deftbsp
temporary tablespace &temptbsp
profile default;

create user ssw identified by ssw
default tablespace &deftbsp
temporary tablespace &temptbsp
profile default;

grant create session to ctw,ssw;

grant create table, select any table to ctw,ssw;

grant create procedure, create type to ctw;

alter user &user quota unlimited on &tbsp;

conn ssw

create table ssw.orders
(ORDER_ID      NUMBER(10)  NOT NULL,
ACCOUNT_ID     NUMBER(10)  NOT NULL,
ORDER_STATUS   NUMBER(3)  NOT NULL)
pctfree 0;

create table ssw.order_items
(ORDER_ID      NUMBER(10)  NOT NULL,
 ORDER_ITEM_ID  NUMBER(10)  NOT NULL,
 SHIP_ID        NUMBER(10))
pctfree 0;

insert into ssw.orders
(order_id,account_id,order_status)
values(3007,2376878,1)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3007,5113492,3254581)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3007,3004,null)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3007,692050,4534)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3007,1667964,896468)
/
insert into ssw.orders
(order_id,account_id,order_status)
values(3004,877686,1)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3004,5113293,3253170)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3004,3001,nul)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3004,690712,4105)
/
insert into ssw.order_items
(order_id,order_item_id,ship_id)
values(3004,1667848,896338)
/
commit
/

conn ctw

create or replace type array is table of varchar2(2000);
/

create or replace package types as type rc is ref cursor;
end;
/

create or replace procedure built_query_ret_result (p_colnames in 
array,p_operator in array, p_values in array,
p_values_operin in array,p_selqntcol in number, p_query in varchar2, 
l_ret_accid_tab out dbms_sql.Number_Table,l_ret_ordid_tab out  
dbms_sql.Number_Table,
l_ret_ordstat_tab out dbms_sql.Number_Table,l_ret_orditid_tab out 
dbms_sql.Number_Table,
l_ret_shipid_tab out  dbms_sql.Number_Table ) as
--
l_cursor int default dbms_sql.open_cursor;
l_query           long;
l_cond_oper       varchar2(20) default ' ';
l_comma           varchar2(1)  default '';
l_status          int;
l_columvalue      varchar2(4000);
l_in_flag         varchar2(1) default 'N';
l_nullval_flag    varchar2(1) default 'N';
l_accid_tab       dbms_sql.Number_Table;
l_ordid_tab       dbms_sql.Number_Table;
l_ordstat_tab     dbms_sql.Number_Table;
l_orditid_tab     dbms_sql.Number_Table;
l_shipid_tab      dbms_sql.Number_Table;
l_indx number := 10;
begin
 if p_values is null then
  l_nullval_flag:='Y';
 end if;
 if p_values_operin is not null then
  l_in_flag:='Y';
 end if;
 l_query:=p_query;
 for i in 1 ..p_colnames.count loop
  if upper(p_operator(i))='IN' then
     l_query:=l_query||l_cond_oper||p_colnames(i)||' '||p_operator(i)||' ( ';
     for x in 1 ..p_values_operin.count loop
      l_query:=l_query||l_comma||':bin_inval'||x;
      if x=1 then
        l_comma:=',';
      end if;
     end loop;
     l_query:=l_query||' ) ';
  else
    l_query:=l_query||l_cond_oper||p_colnames(i)||' '||p_operator(i)||' 
'||':bin_var'||i;
  end if;
  l_cond_oper:=' and ';
 end loop;
 dbms_sql.parse(l_cursor, l_query,dbms_sql.native);
 if l_nullval_flag='N' then
   for i in 1..p_values.count loop
     dbms_sql.bind_variable(l_cursor,':bin_var'||i, p_values(i));
   end loop;
 end if;
 if l_in_flag='Y' then
    for i in 1..p_values_operin.count loop
     dbms_sql.bind_variable(l_cursor,':bin_inval'||i, p_values_operin(i));
    end loop;
 end if;
--
dbms_sql.define_array(l_cursor,1,l_ret_accid_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,2,l_ret_ordid_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,3,l_ret_ordstat_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,4,l_ret_orditid_tab,p_selqntcol,l_indx);
dbms_sql.define_array(l_cursor,5,l_ret_shipid_tab,p_selqntcol,l_indx);
--
 l_status:=dbms_sql.execute(l_cursor);
 while (dbms_sql.fetch_rows(l_cursor)>0)
   loop
      dbms_sql.column_value(l_cursor,1,l_ret_accid_tab);
      dbms_sql.column_value(l_cursor,2,l_ret_ordid_tab);
      dbms_sql.column_value(l_cursor,3,l_ret_ordstat_tab);
      dbms_sql.column_value(l_cursor,4,l_ret_orditid_tab);
      dbms_sql.column_value(l_cursor,5,l_ret_shipid_tab);
   end loop;
 for i in 1 .. l_ret_ordid_tab.count loop
dbms_output.put_line(to_char(l_ret_accid_tab(i))||to_char(l_ret_ordid_tab(i))||to_char(l_ret_orditid_tab(i))||
to_char(l_ret_ordstat_tab(i))||to_char(l_ret_shipid_tab(i)));
 end loop;
   dbms_Sql.close_Cursor(l_cursor);
end;
/

create or replace procedure show_result is
v_cursor types.rc;
v_ord_id number default 3007;
v_colnames array      :=array('a.order_id','b.order_item_id');
v_operator array      :=array('=','in');
v_values array        :=array(v_ord_id);
v_values_operin array :=array();
v_query varchar2(4000);
l_ret_accid_tab   dbms_sql.Number_Table;
l_ret_ordid_tab   dbms_sql.Number_Table;
l_ret_ordstat_tab dbms_sql.Number_Table;
l_ret_orditid_tab dbms_sql.Number_Table;
l_ret_shipid_tab  dbms_sql.Number_Table;
v_strsql varchar2(4000);
v_pos number default 0;
i number;
rowquery ssw.order_items%rowtype;
begin
 v_query:='select 
a.account_id,a.order_id,a.order_status,b.order_item_id,b.SHIP_ID '||
          'from ssw.orders a , ssw.order_items b '||
          'where b.order_id=a.order_id and';
 i:=1;
 select count(*) into v_pos from ssw.order_items where order_id=v_ord_id;
 v_values_operin.extend(v_pos);
 v_strsql:='select * from ssw.order_items where order_id=:xord_id';
 open v_cursor for v_strsql using v_ord_id;
 loop 
    fetch v_cursor into rowquery;
    exit when v_cursor%notFound;
    v_values_operin(i):=rowquery.order_item_id;
    i:=i+1;
 end loop;
built_query_ret_result(v_colnames,v_operator,v_values,v_values_operin,v_pos,v_query,l_ret_accid_tab,l_ret_ordid_tab,l_ret_ordstat_tab,l_ret_orditid_tab,l_ret_shipid_tab);
 dbms_output.put_line('l_ret_ordid_tab.count='||to_char(l_ret_ordid_tab.count));
 for i in 1 .. l_ret_ordid_tab.count loop
dbms_output.put_line(to_char(l_ret_accid_tab(i))||to_char(l_ret_ordid_tab(i))||to_char(l_ret_orditid_tab(i))||
to_char(l_ret_ordstat_tab(i))||to_char(l_ret_shipid_tab(i)));
 end loop;
end;
/

Here you have the results for the test:

SQL>set serveroutput on
SQL>exec show_result;
BEGIN show_result; END;

*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "CTW.BUILT_QUERY_RET_RESULT", line 76
ORA-06512: at "CTW.SHOW_RESULT", line 34
ORA-06512: at line 1

 

Tom Kyte
March 27, 2003 - 7:29 am UTC

I need to write a book on how to make a simple, small, concise, to the point test case....

Anyway, add this DEBUG code:

65 l_status:=dbms_sql.execute(l_cursor);
66 while (dbms_sql.fetch_rows(l_cursor)>0)
67 loop
68 dbms_sql.column_value(l_cursor,1,l_ret_accid_tab);
69 dbms_sql.column_value(l_cursor,2,l_ret_ordid_tab);
70 dbms_sql.column_value(l_cursor,3,l_ret_ordstat_tab);
71 dbms_sql.column_value(l_cursor,4,l_ret_orditid_tab);
72 dbms_sql.column_value(l_cursor,5,l_ret_shipid_tab);
73 end loop;
74
75 dbms_output.put_line( 'accid_tab.count = ' || l_ret_accid_tab.count );
76 dbms_output.put_line( 'ordid_tab.count = ' || l_ret_ordid_tab.count );
77 dbms_output.put_line( 'ordstat_tab.count = ' || l_ret_ordstat_tab.count );
78 dbms_output.put_line( 'orditid_tab.count = ' || l_ret_orditid_tab.count );
79 dbms_output.put_line( 'shipid_tab.count = ' || l_ret_shipid_tab.count );
80
81 dbms_output.put_line( 'accid_tab.first = ' || l_ret_accid_tab.first );
82 dbms_output.put_line( 'ordid_tab.first = ' || l_ret_ordid_tab.first );
83 dbms_output.put_line( 'ordstat_tab.first = ' || l_ret_ordstat_tab.first );
84 dbms_output.put_line( 'orditid_tab.first = ' || l_ret_orditid_tab.first );
85 dbms_output.put_line( 'shipid_tab.first = ' || l_ret_shipid_tab.first );
86
87
88 dbms_output.put_line( 'accid_tab.last = ' || l_ret_accid_tab.last );
89 dbms_output.put_line( 'ordid_tab.last = ' || l_ret_ordid_tab.last );
90 dbms_output.put_line( 'ordstat_tab.last = ' || l_ret_ordstat_tab.last );
91 dbms_output.put_line( 'orditid_tab.last = ' || l_ret_orditid_tab.last );
92 dbms_output.put_line( 'shipid_tab.last = ' || l_ret_shipid_tab.last );
93
94 for i in 1 .. l_ret_ordid_tab.count loop
95 dbms_output.put_line(to_char(l_ret_accid_tab(i))||
96 to_char(l_ret_ordid_tab(i))||
97 to_char(l_ret_orditid_tab(i))||
98 to_char(l_ret_ordstat_tab(i))||
99 to_char(l_ret_shipid_tab(i)));
100 end loop;


and all will be revealed to you. you told us to start the array indexing at 10 (.first will show you that). The array subscripts run from 10..265 in your case, not 1..N....

A little debug code goes a long way...

The smaller a test case is -- the better. 99 times out of 100 in the development of a test case to demonstrate a "product issue", I find the bug in my code ;)




no data found, oracle 7.1.3, might be a bug

rachru, March 27, 2003 - 5:38 am UTC

Well, I do remember we had a similar phaenomenon years ago using oracle 7.x.x.x on HP-UX. It did go wrong occasionally, very strange.

I was able to produce a clear case and oracle was sending a patch. Never had any trouble afterwards.



Tom Kyte
March 27, 2003 - 8:12 am UTC

nope, this is "end user coding error"

No data found using arrays with dbms_sql (cont.)

A reader, March 27, 2003 - 1:42 pm UTC

Tom,
Thank you very much for you help.
I did ran a debug on the code but I always tried to access to the first position in the array. I never thought that the problem was connected with the way I had defined the array. If I were used the .first and .last it would have be more easy to see the error. My mistake for not having done a good debug.

One more thing, I never said that my problem was caused by a bug in the product. I knew all the time that I was doing something wrong in my code, the problem was I could not figure out where I had the error.

Thanks again for your help.

Tom Kyte
March 27, 2003 - 2:15 pm UTC

I was referring to the other persons comment, not yours, when I said "not a product issue, coding issue"

great!, but... do I need an EXTPROC or ?

George Liblick, March 03, 2004 - 2:16 pm UTC

Tom,

I hope you'll forgive me for posting a question here, but I don't know where else to turn...  I've scoured your site, (one of) your book, and the Oracle Documentation.  Lots of help on how to implement a dynamic, bulk select statement.  But, and I'm surprised its not more common, I can't find any showing how to select a variable number of columns into ae expandable two dimensional array.

Can you confirm if this can be done, has to be done in a C-OCI program, or can't :-(

My current effort/example:

CREATE OR REPLACE procedure XX
is
   dyncursor     INTEGER default dbms_sql.open_cursor;
   sqlstmt varchar2(32767);
   column_count integer := 3;
   type datacells_t is table of dbms_sql.varchar2_table index by binary_integer;
   datacells datacells_t;
   onecell dbms_sql.varchar2_table;
   rowcount integer;
   display_line VARCHAR2(256);
BEGIN
   -- in production, sqlstmt is built from table data
   sqlstmt:= 'select username, user_id, created from all_users';

   dbms_sql.parse( dyncursor, sqlstmt, dbms_sql.native );

   FOR i in 1..column_count LOOP
      dbms_sql.DEFINE_ARRAY( dyncursor, i, datacells(i), 100, 1 );
   END LOOP;

   rowcount := dbms_sql.execute( c => dyncursor );
   LOOP
      rowcount := dbms_sql.fetch_rows( c => dyncursor );

      FOR j in 1..column_count LOOP
         dbms_sql.column_value( dyncursor, j, datacells(j) );
      END LOOP;

      FOR i in 1..rowcount LOOP
         display_line := 'ROW ' || i ;
         FOR j in 1..column_count LOOP
            display_line := ', ' || display_line || datacells(j)(i);
         END LOOP;
         dbms_output.put_line( display_line );
      END LOOP;

      EXIT WHEN rowcount <> 100;
   END LOOP;
END;
/

Procedure created.

SQL> exec xx
BEGIN xx; END;

*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "ARIACORE.XX", line 18
ORA-06512: at line 1

...

If I replace the return variable in the DEFINE_ARRAY with "onecell" as defined in that example, everything is OK except that I can't look ahead across the columns, something I need to do.  Right now I'm doing all this without array processing, but its really slow :-(

Thanks so much,

George 

Tom Kyte
March 03, 2004 - 4:05 pm UTC

well, it doesn't work that way. We can do this -- but using a single dimensioned array and reserving:

1 .. Array_Size for column 1
Array_size+1 .. 2*Array_size for column 2 

and so on.  Here is an example:


ops$tkyte@ORA9IR2> create or replace procedure dbms_sql_select
  2  as
  3      l_theCursor     integer default dbms_sql.open_cursor;
  4      l_columnValue   dbms_sql.varchar2_table;
  5      l_empty         dbms_sql.varchar2_table;
  6      l_status        integer;
  7      l_cnt           number := 0;
  8      l_start  number default dbms_utility.get_time;
  9      l_descTbl       dbms_sql.desc_tab;
 10      l_colCnt        number;
 11      l_array_size    number := 10;
 12  begin
 13
 14      dbms_sql.parse( l_theCursor,
 15                     'select username, user_id, created from all_users',
 16                      dbms_sql.native );
 17
 18      dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );
 19
 20      for i in 1 .. l_colCnt
 21      loop
 22          dbms_sql.define_array
 23          ( l_theCursor, i, l_columnValue,
 24            l_array_size, (i-1)*l_array_size+1 );
 25      end loop;
 26
 27      l_status := dbms_sql.execute( l_theCursor );
 28      loop
 29          l_status := dbms_sql.fetch_rows(l_theCursor);
 30          for i in 1 .. l_colCnt
 31          loop
 32              dbms_sql.column_value(l_theCursor,i,l_columnValue);
 33          end loop;
 34
 35          for i in 0 .. l_status-1
 36          loop
 37              for j in 0 .. l_colCnt-1
 38              loop
 39                  dbms_output.put( ' col(' || (j+1) || ')= ' ||
 40                     l_columnValue( (l_columnValue.first+i) + (j*l_array_size) )
 41                  );
 42              end loop;
 43              dbms_output.new_line;
 44          end loop;
 45
 46          l_cnt := l_status+l_cnt;
 47          exit when l_status <> l_array_size;
 48          l_columnValue := l_empty;
 49      end loop;
 50      dbms_sql.close_cursor( l_theCursor );
 51      dbms_output.put_line( L_cnt || ' rows processed' );
 52  end;
 53  /
 
Procedure created.


ops$tkyte@ORA9IR2> exec dbms_sql_select
col(1)= SYS col(2)= 0 col(3)= 12-MAY-02
col(1)= SYSTEM col(2)= 5 col(3)= 12-MAY-02
col(1)= OUTLN col(2)= 11 col(3)= 12-MAY-02
col(1)= DBSNMP col(2)= 19 col(3)= 12-MAY-02
col(1)= WMSYS col(2)= 21 col(3)= 12-MAY-02
col(1)= ORDSYS col(2)= 30 col(3)= 12-MAY-02
col(1)= ORDPLUGINS col(2)= 31 col(3)= 12-MAY-02
col(1)= MDSYS col(2)= 32 col(3)= 12-MAY-02
col(1)= CTXSYS col(2)= 33 col(3)= 12-MAY-02
col(1)= XDB col(2)= 35 col(3)= 12-MAY-02
col(1)= ANONYMOUS col(2)= 36 col(3)= 12-MAY-02
col(1)= WKSYS col(2)= 39 col(3)= 12-MAY-02
col(1)= WKPROXY col(2)= 40 col(3)= 12-MAY-02
col(1)= ODM col(2)= 44 col(3)= 12-MAY-02
col(1)= ODM_MTR col(2)= 45 col(3)= 12-MAY-02
col(1)= LBACSYS col(2)= 42 col(3)= 12-MAY-02
col(1)= OLAPSYS col(2)= 46 col(3)= 12-MAY-02
col(1)= HR col(2)= 48 col(3)= 12-MAY-02
col(1)= OE col(2)= 49 col(3)= 12-MAY-02
col(1)= PM col(2)= 50 col(3)= 12-MAY-02
col(1)= SH col(2)= 51 col(3)= 12-MAY-02
col(1)= QS_ADM col(2)= 53 col(3)= 12-MAY-02
col(1)= QS col(2)= 54 col(3)= 12-MAY-02
col(1)= QS_WS col(2)= 55 col(3)= 12-MAY-02
col(1)= QS_ES col(2)= 56 col(3)= 12-MAY-02
col(1)= QS_OS col(2)= 57 col(3)= 12-MAY-02
col(1)= QS_CBADM col(2)= 58 col(3)= 12-MAY-02
col(1)= QS_CB col(2)= 59 col(3)= 12-MAY-02
col(1)= QS_CS col(2)= 60 col(3)= 12-MAY-02
col(1)= OPS$TKYTE col(2)= 105 col(3)= 03-MAR-04
col(1)= A col(2)= 104 col(3)= 03-MAR-04
col(1)= BIG_TABLE col(2)= 63 col(3)= 28-NOV-03
col(1)= DEMO col(2)= 64 col(3)= 28-NOV-03
col(1)= U1 col(2)= 81 col(3)= 26-DEC-03
col(1)= IOT_HEAP col(2)= 102 col(3)= 06-FEB-04
col(1)= UTILITY col(2)= 70 col(3)= 28-NOV-03
col(1)= DEMO002 col(2)= 71 col(3)= 28-NOV-03
col(1)= DEMO006 col(2)= 72 col(3)= 28-NOV-03
col(1)= DEMO007 col(2)= 73 col(3)= 28-NOV-03
col(1)= DEMO008 col(2)= 74 col(3)= 28-NOV-03
col(1)= PERFSTAT col(2)= 82 col(3)= 02-JAN-04
col(1)= FLOWS_FILES col(2)= 83 col(3)= 06-JAN-04
col(1)= HTMLDB_PUBLIC_USER col(2)= 84 col(3)= 06-JAN-04
col(1)= FLOWS_010404 col(2)= 85 col(3)= 06-JAN-04
col(1)= DEMO_SCHEMA col(2)= 86 col(3)= 06-JAN-04
col(1)= SERGIO col(2)= 87 col(3)= 06-JAN-04
col(1)= AUTOTRACE_EXAMPLE col(2)= 99 col(3)= 16-JAN-04
col(1)= SCOTT col(2)= 92 col(3)= 14-JAN-04
48 rows processed
 
PL/SQL procedure successfully completed.
 

splendifico!

George Liblick, March 03, 2004 - 6:01 pm UTC

well, it would be nice if it worked... but this is a pretty good substitute for a true 2D array - it took me a minute to realize that the array size isn't limiting but rather the fetch size, after that I don't see any real drawback..?

and, your prompt help is very much appreciated :-)

George

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