Home » SQL & PL/SQL » SQL & PL/SQL » Oracle PL/SQL Collection (Oracle 9i)
Oracle PL/SQL Collection [message #322919] |
Mon, 26 May 2008 19:42 |
majsaxar
Messages: 4 Registered: May 2008 Location: Atlanta
|
Junior Member |
|
|
I am new to this topic and I need some help on this. Here is what I have. I have an array of rows passed to a stored proc. which is not show here. I am working on a proof of concept.
Foe exmaple this row '1,1,54,1,1,1' is actually the values of six columns to be inserted and I want the whole thing to a bulk binding. Instead of reading one raw at a time and hitting the database I want to pass as a one dimensional array as shown below. But so far with no luck. I created a table called my_test_Table with six columns. Any input
DECLARE
TYPE my_test_tbl
IS TABLE OF VARCHAR2(32767);
my_test_tbl _list my_test_tbl ;
BEGIN
my_test_tbl _list (1):='1,1,54,1,1,1';
my_test_tbl _list (2):='2,1,12,1,1,1';
my_test_tbl _list (3):='3,1,15,1,1,1';
my_test_tbl _list (4):='4,1,19,1,1,1';
my_test_tbl _list (5):='5,1,20,1,1,1';
my_test_tbl _list (6):='6,1,23,1,1,1';
my_test_tbl _list (7):='7,1,24,1,1,1';
FORALL indx IN my_test_tbl _list .First..my_test_tbl_list .Last -- line 36, column 4 just before the FORALL
INSERT INTO my_test_Table
VALUES my_test_tbl _list (indx); --line 37 column 12 is begining of my_test_tbl _list
END;
I am getting the following error messages
ORA-06550: line 37, column 12:
PL/SQL: ORA-00904: : invalid identifier
ORA-06550: line 36, column 4:
PL/SQL: SQL Statement ignored
|
|
|
|
Re: Oracle PL/SQL Collection [message #322925 is a reply to message #322920] |
Mon, 26 May 2008 20:58 |
majsaxar
Messages: 4 Registered: May 2008 Location: Atlanta
|
Junior Member |
|
|
I did not quite get what your question is referring, but what I presented here is out there in the literature, but simply it did not work for me.
Normally one will write an Insert statement in plain SQL as follows:
INSERT INTO <table_name> VALUES(a,b,c,..,k)
however in Oracle collection (Associative arrays, nested tables and Varrays) together with the FORALL key word which is used instead of the For loop, what I have written in my earlier posting is what is out there. Thanks for your response.
Jama A
|
|
|
|
|
Re: Oracle PL/SQL Collection [message #322982 is a reply to message #322947] |
Tue, 27 May 2008 00:14 |
pointers
Messages: 451 Registered: May 2008
|
Senior Member |
|
|
Can't we insert all column values at a time into the individual record at a time.
something like
my_test_tbl _list (1):='1,1,54,1,1,1'; --but this is not working
Regards,
Pointers
|
|
|
Re: Oracle PL/SQL Collection [message #323134 is a reply to message #322919] |
Tue, 27 May 2008 07:16 |
JRowbottom
Messages: 5933 Registered: June 2006 Location: Sunny North Yorkshire, ho...
|
Senior Member |
|
|
The problem is that you are assuming that a comma separated list of fields:INSERT INTO demo_table VALUES (1,2,3,4,5) and a string containing some values that happen to have commas between themDECLARE
v_str varchar2(100) := '1,2,3,4,5';
BEGIN
INSERT INTO demo_table VALUES v_str;
END; should be treated the same.
|
|
|
Re: Oracle PL/SQL Collection [message #323179 is a reply to message #322982] |
Tue, 27 May 2008 10:26 |
|
Barbara Boehmer
Messages: 9100 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
SCOTT@orcl_11g> CREATE TABLE my_test_table
2 (col1 NUMBER,
3 col2 NUMBER,
4 col3 NUMBER,
5 col4 NUMBER,
6 col5 NUMBER,
7 col6 NUMBER)
8 /
Table created.
SCOTT@orcl_11g> CREATE OR REPLACE TYPE my_test_rec AS OBJECT
2 (col1 NUMBER,
3 col2 NUMBER,
4 col3 NUMBER,
5 col4 NUMBER,
6 col5 NUMBER,
7 col6 NUMBER);
8 /
Type created.
SCOTT@orcl_11g> CREATE OR REPLACE TYPE my_test_tbl AS TABLE OF my_test_rec;
2 /
Type created.
SCOTT@orcl_11g> DECLARE
2 my_test_tbl_list my_test_tbl := my_test_tbl ();
3 BEGIN
4 my_test_tbl_list.EXTEND (7);
5 my_test_tbl_list (1) := my_test_rec (1, 1, 54, 1, 1, 1);
6 my_test_tbl_list (2) := my_test_rec (2, 1, 12, 1, 1, 1);
7 my_test_tbl_list (3) := my_test_rec (3, 1, 15, 1, 1, 1);
8 my_test_tbl_list (4) := my_test_rec (4, 1, 19, 1, 1, 1);
9 my_test_tbl_list (5) := my_test_rec (5, 1, 20, 1, 1, 1);
10 my_test_tbl_list (6) := my_test_rec (6, 1, 23, 1, 1, 1);
11 my_test_tbl_list (7) := my_test_rec (7, 1, 24, 1, 1, 1);
12 INSERT INTO my_test_table
13 SELECT * FROM TABLE (my_test_tbl_list);
14 END;
15 /
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> SELECT * FROM my_test_table
2 /
COL1 COL2 COL3 COL4 COL5 COL6
---------- ---------- ---------- ---------- ---------- ----------
1 1 54 1 1 1
2 1 12 1 1 1
3 1 15 1 1 1
4 1 19 1 1 1
5 1 20 1 1 1
6 1 23 1 1 1
7 1 24 1 1 1
7 rows selected.
SCOTT@orcl_11g>
|
|
|
|
Re: Oracle PL/SQL Collection [message #323574 is a reply to message #323134] |
Wed, 28 May 2008 21:17 |
majsaxar
Messages: 4 Registered: May 2008 Location: Atlanta
|
Junior Member |
|
|
Thank you all for your help.
Barbara Boehmer's solution is close to what I wanted as proof of concept. However, what I will be using is a stored procedure and I will be passing an ARRAY like this. I want bulk insert.
my_test_tbl _list my_test_tbl := my_test_tbl (
'1,1,54,1,1,1',
'2,1,12,1,1,1';
'3,1,15,1,1,1',
'4,1,19,1,1,1',
'5,1,20,1,1,1',
'6,1,23,1,1,1',
'7,1,24,1,1,1'
)
The number of rows is not fixed it can be between 1 to 15. So before any INSERT takes place one has to loop first and remove the single qoutes and then insert one row at a time. Is it possible to use the FORALL constract instead of FOR loop? thanks in advance.
A. Jama
|
|
|
Re: Oracle PL/SQL Collection [message #323584 is a reply to message #322919] |
Wed, 28 May 2008 22:48 |
|
Kevin Meade
Messages: 2103 Registered: December 1999 Location: Connecticut USA
|
Senior Member |
|
|
First let me say, I am not a real fan of bulk operations. I say this not because they don't work as advertised, but rather because I feel they are an excuse for not coding a SQL only solution. Straight SQL without use of plsql is by definition a bulk operation and you can't get any faster.
That said, there are people who just can't give up procedural mindsets, and I suppose living with a NORMAN defeating liar's paradox that there is always an exception to every rule, your forall operation is just a matter of syntax.
Here is one solution. I have no issue giving you the code because you have it all done anyway. The only real contribution I have made here are two:
1) I use the IN INDICES OF syntax of FORALL
2) I use string operations to parse array elements into column values
SQL>
SQL> drop table my_test_tbl;
Table dropped.
SQL>
SQL> create table my_test_tbl (a number,b number,c number,d number,e number,f number);
Table created.
SQL>
SQL> DECLARE
2 TYPE my_test_tbl IS TABLE OF VARCHAR2(32767);
3 my_test_tbl_list my_test_tbl := my_test_tbl();
4 procedure add_row_to_array (string_p in varchar2) is
5 begin
6 my_test_tbl_list.extend;
7 my_test_tbl_list(my_test_tbl_list.last) := string_p;
8 end;
9 BEGIN
10 add_row_to_array ('1,1,54,1,1,1');
11 add_row_to_array ('2,1,12,1,1,1');
12 add_row_to_array ('3,1,15,1,1,1');
13 add_row_to_array ('4,1,19,1,1,1');
14 add_row_to_array ('5,1,20,1,1,1');
15 add_row_to_array ('6,1,23,1,1,1');
16 add_row_to_array ('7,1,24,1,1,1');
17
18 FORALL indx IN INDICES OF my_test_tbl_list
19
20 INSERT INTO my_test_tbl VALUES (
21 substr(
22 ','||my_test_tbl_list(indx)||','
23 ,instr(','||my_test_tbl_list(indx)||',',',',1,1)+1
24 ,instr(','||my_test_tbl_list(indx)||',',',',1,2)-instr(','||my_test_tbl_list(indx)||',',',',1,1)-1
25 )
26 ,substr(
27 ','||my_test_tbl_list(indx)||','
28 ,instr(','||my_test_tbl_list(indx)||',',',',1,2)+1
29 ,instr(','||my_test_tbl_list(indx)||',',',',1,3)-instr(','||my_test_tbl_list(indx)||',',',',1,2)-1
30 )
31 ,substr(
32 ','||my_test_tbl_list(indx)||','
33 ,instr(','||my_test_tbl_list(indx)||',',',',1,3)+1
34 ,instr(','||my_test_tbl_list(indx)||',',',',1,4)-instr(','||my_test_tbl_list(indx)||',',',',1,3)-1
35 )
36 ,substr(
37 ','||my_test_tbl_list(indx)||','
38 ,instr(','||my_test_tbl_list(indx)||',',',',1,4)+1
39 ,instr(','||my_test_tbl_list(indx)||',',',',1,5)-instr(','||my_test_tbl_list(indx)||',',',',1,4)-1
40 )
41 ,substr(
42 ','||my_test_tbl_list(indx)||','
43 ,instr(','||my_test_tbl_list(indx)||',',',',1,5)+1
44 ,instr(','||my_test_tbl_list(indx)||',',',',1,6)-instr(','||my_test_tbl_list(indx)||',',',',1,5)-1
45 )
46 ,substr(
47 ','||my_test_tbl_list(indx)||','
48 ,instr(','||my_test_tbl_list(indx)||',',',',1,6)+1
49 ,instr(','||my_test_tbl_list(indx)||',',',',1,7)-instr(','||my_test_tbl_list(indx)||',',',',1,6)-1
50 )
51 );
52 END;
53 /
PL/SQL procedure successfully completed.
SQL>
SQL> select * from my_test_tbl;
A B C D E F
---------- ---------- ---------- ---------- ---------- ----------
1 1 54 1 1 1
2 1 12 1 1 1
3 1 15 1 1 1
4 1 19 1 1 1
5 1 20 1 1 1
6 1 23 1 1 1
7 1 24 1 1 1
7 rows selected.
SQL>
SQL>
Does this work for you?
Kevin
drop table my_test_tbl;
create table my_test_tbl (a number,b number,c number,d number,e number,f number);
DECLARE
TYPE my_test_tbl IS TABLE OF VARCHAR2(32767);
my_test_tbl_list my_test_tbl := my_test_tbl();
procedure add_row_to_array (string_p in varchar2) is
begin
my_test_tbl_list.extend;
my_test_tbl_list(my_test_tbl_list.last) := string_p;
end;
BEGIN
add_row_to_array ('1,1,54,1,1,1');
add_row_to_array ('2,1,12,1,1,1');
add_row_to_array ('3,1,15,1,1,1');
add_row_to_array ('4,1,19,1,1,1');
add_row_to_array ('5,1,20,1,1,1');
add_row_to_array ('6,1,23,1,1,1');
add_row_to_array ('7,1,24,1,1,1');
FORALL indx IN INDICES OF my_test_tbl_list
INSERT INTO my_test_tbl VALUES (
substr(
','||my_test_tbl_list(indx)||','
,instr(','||my_test_tbl_list(indx)||',',',',1,1)+1
,instr(','||my_test_tbl_list(indx)||',',',',1,2)-instr(','||my_test_tbl_list(indx)||',',',',1,1)-1
)
,substr(
','||my_test_tbl_list(indx)||','
,instr(','||my_test_tbl_list(indx)||',',',',1,2)+1
,instr(','||my_test_tbl_list(indx)||',',',',1,3)-instr(','||my_test_tbl_list(indx)||',',',',1,2)-1
)
,substr(
','||my_test_tbl_list(indx)||','
,instr(','||my_test_tbl_list(indx)||',',',',1,3)+1
,instr(','||my_test_tbl_list(indx)||',',',',1,4)-instr(','||my_test_tbl_list(indx)||',',',',1,3)-1
)
,substr(
','||my_test_tbl_list(indx)||','
,instr(','||my_test_tbl_list(indx)||',',',',1,4)+1
,instr(','||my_test_tbl_list(indx)||',',',',1,5)-instr(','||my_test_tbl_list(indx)||',',',',1,4)-1
)
,substr(
','||my_test_tbl_list(indx)||','
,instr(','||my_test_tbl_list(indx)||',',',',1,5)+1
,instr(','||my_test_tbl_list(indx)||',',',',1,6)-instr(','||my_test_tbl_list(indx)||',',',',1,5)-1
)
,substr(
','||my_test_tbl_list(indx)||','
,instr(','||my_test_tbl_list(indx)||',',',',1,6)+1
,instr(','||my_test_tbl_list(indx)||',',',',1,7)-instr(','||my_test_tbl_list(indx)||',',',',1,6)-1
)
);
END;
/
select * from my_test_tbl;
|
|
|
Re: Oracle PL/SQL Collection [message #323797 is a reply to message #322919] |
Thu, 29 May 2008 08:56 |
majsaxar
Messages: 4 Registered: May 2008 Location: Atlanta
|
Junior Member |
|
|
Thanks Kevin for your help. I agree bulk insert is not some thing to rush. However, if one considers my case of having to loop through rows of data in a web page and reading one row at a time and making multi trips to the database, I decided to store the rows into an string array and passed to the stored proc.
This Kevins solution
procedure add_row_to_array (string_p in varchar2)
in my case
string_p =(
'1,1,54,1,1,1',
'2,1,12,1,1,1',
'3,1,15,1,1,1',
'4,1,19,1,1,1',
'5,1,20,1,1,1',
'6,1,23,1,1,1',
'7,1,24,1,1,1'
)
That is what I want to pass from mu application to the stored procedure.
Kevin could you please elobrate why you have the following in the BEGIN .. END block?
BEGIN
add_row_to_array ('1,1,54,1,1,1');
add_row_to_array ('2,1,12,1,1,1');
add_row_to_array ('3,1,15,1,1,1');
add_row_to_array ('4,1,19,1,1,1');
add_row_to_array ('5,1,20,1,1,1');
add_row_to_array ('6,1,23,1,1,1');
add_row_to_array ('7,1,24,1,1,1');
Because these data is passed to the stored proc ( as string_p params shows). Thank you all for your help.
|
|
|
Re: Oracle PL/SQL Collection [message #324083 is a reply to message #322919] |
Fri, 30 May 2008 13:23 |
|
Kevin Meade
Messages: 2103 Registered: December 1999 Location: Connecticut USA
|
Senior Member |
|
|
Sure, I was hoping it was pretty obvious, but I was loading a string array with string values. The string_p = ... is not a valid pl/sql expression.
SQL> declare
2 string_p varchar2(4000);
3 begin
4 string_p := ('1,2,3','4,5,6','7,8,9');
5 end;
6 /
string_p := ('1,2,3','4,5,6','7,8,9');
*
ERROR at line 4:
ORA-06550: line 4, column 16:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 4, column 4:
PL/SQL: Statement ignored
I assume you were using string_p = ... as a way to load a string array in java and that you are going to pass the string array to plsql. This should work just fine, but you would need to define a database object type to accept it. Something like this:
create or replace type c_string_4000 is table of varchar2(4000);
procedure take_it (string_p in c_string_4000) is...
Then you can call the plsql procedure from java.
Does this answer your question?
Kevin
|
|
|
Goto Forum:
Current Time: Mon Dec 02 08:56:22 CST 2024
|