FORALL statement
I am trying to use FORALL to bulk bind INSERT statements to improve performance.
I replace a FOR .. LOOP command with FORALL as detailed in 8i documentation, and remove the END LOOP.
Yet I get an error when compiling -
"PLS-00707: unsupported construct or internal error [2603]"
Please can someone help me if you've used the command before!
FORALL adds certain limitations on what you can insert. You can only insert arrays of 'basic' types, like integers. You can't use %ROWTYPES or records. The documentation wasn't especially clear when I tried this, but it is worth persevering as it is much quicker.
Oh, and it is a new addition to PL/SQL so I wouldn't discount the possibility that it's an internal error...
Similar Messages
-
BULKING and FORALL statement does not pass values to non DML statements.
Hi
I've got million rows that i need to manapulate and insert into various procedures depending on the bussiness rule to be applied, but my dilemma is that the BULIKNG with a combination of a FORALL statement its not compatible(only considers straightforward DML calls) or the the FORALL does not like other SQL statements or calls as it prefers only DML's.
Below is code fragment that is problamatic as the compiler keeps sending me this error: PLS-00201: identifier 'INDX' must be declared
I want to manupulate data on the implicity cursor and call a procedure to do other stuff which don't use INSERT/DELETE or UPDATE statements.
Declare
TYPE tab_person_id is of table of number(15);
l_person_id tab_person_id;
BEGIN
SELECT person_id
BULK COLLECT INTO l_person_id
FROM person_details; /*-Million records-*/
FORALL indx IN l_tdtl.FIRST..l_tdtl.LAST
pj_pkg.ins_intf
(p_user => p_user,
p_typ_cd => '00',
p_person_id => l_person(indx)
Commit;
END;
How do I pass this value 'l_person(indx)' on the package procudure ?
Thanks
Amos@prabodh:
SQL> declare
2 TYPE tab_person_id is of table of number(15) index by pls_integer;
3 begin
4 null;
5 end;
6 /
TYPE tab_person_id is of table of number(15) index by pls_integer;
ERROR at line 2:
ORA-06550: line 2, column 23:
PLS-00103: Encountered the symbol "OF" when expecting one of the following:
( array limited new private range record VARRAY_ char_base
number_base decimal date_base clob_base blob_base bfile_base
table ref object fixed varying opaque sparse
The symbol "OF" was ignored.Check What you are posting.
@ qwestion: What is your Database Version? It is a implementation restriction. -
How can I run two DML in one FORALL statement?
How can I run 1) select 2) update in one FORALL for each item as below?
OPEN FXCUR;
LOOP
FETCH FXCUR BULK COLLECT INTO v_ims_trde_oids LIMIT 1000;
EXIT WHEN v_ims_trde_oids.COUNT() = 0;
FORALL i IN v_ims_trde_oids.FIRST .. v_ims_trde_oids.LAST
SELECT EXTRACTVALUE(XMLTYPE(CNTNT),'/InboundGTMXML/ProcessingIndicators/ClientCLSEligibleIndicator') INTO v_cls_ind
FROM IMS_TOMS_MSGE WHERE ims_trde_oid = v_ims_trde_oids(i);
IF v_cls_ind IS NOT NULL THEN
v_cls_ind := '~2136|S|'||v_cls_ind||'|';
UPDATE ims_alctn_hstry SET CHNGE_DATA_1 =concat(CHNGE_DATA_1,v_cls_ind)
WHERE ims_trde_hstry_id = (select max(ims_trde_hstry_id) from ims_alctn_hstry where ims_trde_oid=v_ims_trde_oids(i));
DBMS_OUTPUT.PUT_LINE('Trade oid: '||v_ims_trde_oids(i)||' CLS Eligible Indicator: '||v_cls_ind);
END IF;
END LOOP;
CLOSE FXCUR;Your help will be appreciated.
Thanks
Edited by: PhoenixBai on Aug 6, 2010 6:05 PMI came through this forum while googling on the issue of 'using two DML's in one FORALL statement.
Thanks for all the useful information guys.
I need to extend this functionality a bit.
My present scenario is as follows:
FOR I in 1..collection1.count Loop
BEGIN
insert into tab1(col1)
values collection1(I) ;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR('ERROR AT'||collection1(I));
END;
BEGIN
UPDATE tab2
SET col1 = collection1(I);
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR('ERROR AT'||collection1(I));
END;
commit;
END LOOP;
I need to use the FORALL functionality in this scenario, but without using the SAVE EXCEPTIONS clause keeping in mind that I also need to get value in the
collection that led to the error.Also, the each INSERT statement has to be followed by an UPDATE and then the cycle goes on(Hence I cannot use 2 FORALL statements for INSERT and UPDATE coz then all the INSERT will be performed at once and similarly the UPDATEs). So I created something like this:
DECLARE
l_stmt varchar2(1000);
BEGIN
l_stmt := 'BEGIN '||
'insert into tab1(col1) '||
'values collection1(I) ; '||
'EXCEPTION '||
'WHEN OTHERS THEN '||
'RAISE_APPLICATION_ERROR(''ERROR AT''|| :1); '||
'END; '||
'BEGIN '||
'UPDATE tab2 '||
'SET col1 = :1; '||
'EXCEPTION '||
'WHEN OTHERS THEN '||
'RAISE_APPLICATION_ERROR(''ERROR AT''|| :1); '||
'END;'
FORALL I in 1..collection1.count
EXECUTE IMMEDIATE l_stmt USING Collection1(SQL%BULK_EXCEPTIONS(1).ERROR_INDEX);
END;
Will this approach work? Or is there any better aproach to this? I am trying to avoid the traditional FOR ..LOOP to achieve better performance of query -
Update query using FORALL statement
Hi ALL,
I have two tables Table: Mater_A(20 Cloumns) and Temp_A(20 Columns).
Both are almost identical. The Master_A is master table that has to be updated daily based on the temporary table Temp_A.
Everyday , i expect around 100000 records(same records with modified valus ) in Temp_A that has to be updated in Master_A. So i have to make the query as optimized as possible.
For this,I have created a cursor that has all records from table Temp_A.
Then i am using FORALL statement to update the data. But it throws exception something like that:
Error: PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records
Error: PLS-00382: expression is of wrong type
It states that i have to create a separate type for each column that i want to update.
I have created procedure like this:
Open C_Temp_A;
Loop
Fetch C_Temp_A Bulk Collect into v_C_Temp_A limit 5000;
Exit When C_Temp_A%NOTFOUND;
Begin
ForAll i in v_C_Temp_A.first.. v_C_Temp_A.Last
Update Master_A mst Set mst.Column2= v_C_Temp_A(i).t_Column2,
mst.Column3= v_C_Temp_A(i).t_Column3,mst.Column4= v_C_Temp_A(i).t_Column4........to all columns
where mst.Column1= v_C_Temp_A(i).t_Column1;
End;
End Loop;
Close C_Temp_A;
Please help me to solve this or suggest me any other alternative to reduce the processing time.Why cant you use like :(Or I misread?)
SQL> select * from a;
ID C2
1 100
SQL> select * from b;
ID C2
1 1000
SQL> merge into b
2 using(select * from a) a
3 on (b.id = a.id)
4 when matched then
5 update
6 set b.c2 = a.c2;
1 row merged.
SQL> select * from b;
ID C2
1 100 -
Binds collections and forall statement
version 9.2.0.6
I would like to make this more dynamic in that the collection cList can be used only once and be used by all bind variables. The variable stmt would be dynamically generated in that case it would insert into any number of tables.
Can this be done?
Is this feature available in a newer version of Oracle?
create table d2 nologging as
select
rownum rn
,substr(dbms_random.string('x',5),1,10) v1
,sysdate d1
,round(dbms_random.value(1,10)) n1
,substr(dbms_random.string('x',5),1,10) v2
,rpad(' ',4000,' ') as concat
from dual connect by level <= 100;
-- no rows for our test
create table d3 nologging as
select
from d2 where 1 = 2;
-- setup for our test
update d2
set image = rpad(nvl(to_char(rn),' '),10,' ')
|| rpad(nvl(v1,' '),20,' ')
|| rpad(nvl(to_char(d1,'DD-MON-YYYY HH24:MI:SS'),' '),34,' ')
|| rpad(nvl(to_char(n1),' '),10,' ')
|| rpad(nvl(v2,' '),10,' ')
-- test got all locations right
select
to_number(rtrim(substr(image,1,10)))
,rtrim(substr(image,11,20))
,to_date(rtrim(substr(image,30,34)),'DD-MON-YYYY HH24:MI:SS')
,to_number(rtrim(substr(image,65,10))) AS n1
,rtrim(substr(image,75,10))
from d2;
-- here is where we do the work
declare
type charList is table of varchar2(4000);
cList charList;
d2l d2_list;
errors NUMBER;
dml_errors EXCEPTION;
PRAGMA exception_init(dml_errors, -24381);
sqlStmt varchar2(32000);
cursor cur is select image from d2;
bcLimit number := 23;
begin
sqlStmt := 'insert into d3 (rn,v1,d1,n1,v2)'
|| 'values (to_number(rtrim(substr(:a,1,10)))
,rtrim(substr(:a,11,20))
,to_date(rtrim(substr(:a,30,34)),''DD-MON-YYYY HH24:MI:SS'')
,to_number(rtrim(substr(:a,65,10)))
,rtrim(substr(:a,75,10)))';
open cur;
loop
fetch cur bulk collect into cList limit bcLimit;
exit when cList.count = 0;
begin
-- very very unfortunately the code is unable to have one using clause variable be applied to all bind variables
-- note the number of cList uses having the bind variables all name the same does not help
-- using only one gets a ORA-1008 error :(
FORALL i IN cList.FIRST..cList.LAST SAVE EXCEPTIONS execute immediate sqlstmt using cList(i),cList(i),cList(i),cList(i),cList(i);
-- FORALL i IN cList.FIRST..cList.LAST SAVE EXCEPTIONS execute immediate sqlstmt using cList(i); --< DOES NOT WORK :( I WISH IT WOULD!
EXCEPTION
WHEN dml_errors THEN
errors := SQL%BULK_EXCEPTIONS.COUNT;
dbms_output.put_line('number of errors is ' || errors);
FOR i IN 1..errors LOOP
dbms_output.put_line('Error ' || i || ' occurred during iteration ' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
dbms_output.put_line('Could not insert ' || cList(SQL%BULK_EXCEPTIONS(i).ERROR_INDEX));
dbms_output.put_line(SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
end;
end loop;
close cur;
dbms_output.put_line('h2');
end;
/The CREATE TABLE you post for table D2 has no column called 'image'. It would help somewhat if you posted a working example.
Also I am not clear why the INSERT INTO D3 statement in the anonymous block needs to be dynamic. -
Can we use dbms_output.put_line package with forall statement
Hello Everybody
Can we use dbms_output.put_line package with forall or can we use insert,update and delete only
declare
type emp_rec is table of emp%rowtype
index by binary_integer;
t emp_rec;
begin
select * bulk collect into t from emp;
forall i in t.first..t.last
dbms_output.put_line(t(i).name);
end;Thanks & Regards
peeyush
Edited by: Peeyush on Nov 25, 2010 11:45 PMMichaelS wrote:
Well as the docs explain (though not very clear and detailed, I admit) you can use a dynamic sql statement (execute immediate) with FORALL.You got me interested in the performance side doing this Michael - running PL/SQL code via a FORALL loop.
It is faster than using a normal FOR loop to execute dynamic PL/SQL - a bit surprising as I expected another context switch to be in there. But seems like the PL/SQL engine is a more clever at optimisation than what I originally credited it with.. ;-)
Of course - pre-compiled/static PL/SQL code in a FOR loop is the fastest, as expected.
SQL> declare
2 type TNumbers is table of number;
3
4 type TTimes is record(
5 for_all number,
6 for_dynamic number,
7 for_static number
8 );
9
10 type TTimesTable is table of TTimes;
11
12 MAX_ITERATIONS constant number := 10;
13
14 plBlock varchar2(1000) :=
15 'declare i number;
16 begin i:= :var / 10; end;';
17
18 performance TTimesTable;
19 t1 number;
20 bindVar TNumbers;
21 n number;
22 begin
23 select
24 level bulk collect into bindVar
25 from dual
26 connect by level <= 10000;
27
28 dbms_output.put_line( 'Iterations: '||bindVar.Count||' for loop cycle(s)' );
29
30 performance := new TTimesTable();
31 performance.Extend( MAX_ITERATIONS );
32
33 for j in 1..MAX_ITERATIONS
34 loop
35 t1 := dbms_utility.get_time;
36 forall i in 1..bindVar.Count
37 execute immediate plBlock using bindVar(i);
38 performance(j).for_all := dbms_utility.get_time-t1;
39
40 t1 := dbms_utility.get_time;
41 for i in 1..bindVar.Count
42 loop
43 execute immediate plBlock using bindVar(i);
44 end loop;
45 performance(j).for_dynamic := dbms_utility.get_time-t1;
46
47 t1 := dbms_utility.get_time;
48 for i in 1..bindVar.Count
49 loop
50 n := bindVar(i) / 10;
51 end loop;
52 performance(j).for_static := dbms_utility.get_time-t1;
53 end loop;
54
55 dbms_output.put_line( 'Times in 100th of a second' );
56 dbms_output.put_line( rpad('for all',15) || rpad('for dynamic',15) || rpad('for static',15) );
57 for i in 1..performance.Count
58 loop
59 dbms_output.put_line(
60 rpad( performance(i).for_all, 15 )||' '||
61 rpad( performance(i).for_dynamic, 15 )||' '||
62 rpad( performance(i).for_static, 15)
63 );
64 end loop;
65
66 end;
67 /
Iterations: 10000 for loop cycle(s)
Times in 100th of a second
for all for dynamic for static
10 72 0
6 37 0
6 37 0
6 37 0
6 36 0
6 37 1
5 37 0
5 37 0
6 37 1
5 37 0
PL/SQL procedure successfully completed.
SQL> -
Is limiting needed in forall statements?
Hello,
Could you please help me understand what the advantage is (if any) of looping and limiting during forall updates? I saw this simplified version in one the programs here at work and don't understand what the looping and limiting is for.
declare
cursor c1 is
select column1, column2 from tablea;
type aaa is table of c1%rowtype;
var1 aaa;
begin
open c1;
loop
fetch bulk collect into var1 limit 2500;
forall i in var1.first .. var1.last
update tableb
set column2 = var1(i).column2
where column1 = var1(i).column1;
exit when var1.count < 2500;
end loop;
close c1;
end;arizona9952 wrote:
Hello,
Could you please help me understand what the advantage is (if any) of looping and limiting during forall updates? I saw this simplified version in one the programs here at work and don't understand what the looping and limiting is for.The advantage is that you can control the amount of memory your process needs to consume (PGA). There is a finite amount on every system, the amount available to you will depend on a number of factors (do some research if you're interested in this).
In my opinion you should always be using LIMITs when performing bulk operations.
As an aside, the code you've posted could be done as a single UPDATE statement (or MERGE), in about 95% of the cases you'll be better off with a single SQL statement if you can get away with it. -
Using Sequence in FORALL Statement
I'm using a package to get the nextval in a sequence object. Basically, it is a function that returns select user_seq.nextval from dual.
But I get 'column not allowed here' error. PL/SQL: ORA-00984: column not allowed here
OPEN users_ins ;
LOOP
FETCH naf_users_ins
BULK COLLECT
INTO arr_person_key
, arr_person_id
, arr_first_name
, arr_middle_name
, arr_last_name
, arr_username
, arr_user_status_seq
, arr_creation_date
, arr_comments
LIMIT 100 ;
FORALL idx IN 1 .. arr_person_key.COUNT
SAVE EXCEPTIONS
INSERT INTO users
( user_seq
, person_key
, person_id
, first_name
, middle_name
, last_name
, username
, user_status_seq
, creation_date
, comments
VALUES ( *pkg_admin.get_nextval*
, arr_person_key(idx)
, arr_person_id(idx)
, arr_first_name(idx)
, arr_middle_name(idx)
, arr_last_name(idx)
, arr_username(idx)
, arr_user_status_seq(idx)
, arr_creation_date(idx)
, arr_comments(idx)
EXIT WHEN users_ins%NOTFOUND ;
END LOOP ;
CLOSE users_ins;
c/code]Hi,
I've recently completed a similar task, but I declared a collection with the rowtype of the table. I also added the sequence in the query of my cursor. Take a look at the following example.
CREATE OR REPLACE PROCEDURE Insert_OR_ExternalService
IS
TYPE externalService_tbl IS TABLE OF OR_ExternalService%ROWTYPE;
externalService externalService_tbl;
CURSOR OR_ExternalServiceCursor
IS
select
SEQ_ID.NEXTVAL as "Id",
column as "ExternalId",
column as "ExternalSystem",
from table1
where ...;
BEGIN
OPEN OR_ExternalServiceCursor;
LOOP
FETCH OR_ExternalServiceCursor BULK COLLECT INTO externalService LIMIT 1000;
FORALL i IN 1 .. externalService.count
INSERT INTO OR_ExternalService values externalService(i);
COMMIT;
EXIT WHEN OR_ExternalServiceCursor%NOTFOUND;
END LOOP;
CLOSE OR_ExternalServiceCursor;
END; -
Hi all,
I've been trying to Bulk Insert into a table using a collection of records. According to the documentation, composite values are not decomposed automatically, and so they must be decomposed manually. The part of the documentation I'm referring to is in the following link, FORALL restrictions, point (6).
http://otn.oracle.com/docs/products/oracle9i/doc_library/release2/appdev.920/a96624/13_elems22.htm#34325
The problem is that the workaround that's been provided does not work as it is in the documentation. The error is 'PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records'. I'm not sure what they've mentioned could be done at all. Does anyone know if it's possible ?
Thanks.I've worked with the Bulk Bind of %ROWTYPE collections, but in situations when you're working with tables with a large number of columns, and you have a considerable percentage of the columns having the same value for all rows during a single BULK operation, it's not elegant to have all these columns, say, ENTRY_DATE, or USERNAME, repeating throughout your collection.
For example, If I have a table with 50 columns, and during a single bulk insert, about 15 of the columns have the same value for all rows. I was wondering if it would be possible to insert like this :
FORALL I IN FIRST..LAST
INSERT INTO <TABLE>
(COL1, COL2,...,COL35, COL36,..., COL50)
VALUES
(COLLECTION(I).COL1, COLLECTION(I).COL2,...,COLLECTION(I).COL35, CONSTANT1, CONSTANT2, ETC.);
I hope you get the picture. I tried this kind of INSERT, but was not able to do it on a 9.2 server. I guess a workaround would be necessary. Anyway, your answer shed some clarity on my question.
Thank You. -
Other database delete is not working on forall statement
Dear all,
My scenario is , i create a program, the program fetch the data from database x and i want to delete on the same x database but i am running this program at y database, so
so i created a view
create or replace view vw_ibs_pda_bills_x as
SELECT *
FROM ibs_pda_bills_x@testarch1my program
Declare
CURSOR c2 IS
SELECT *
FROM vw_ibs_pda_bills_x
WHERE bill_month <= '31-dec-2008'; -- AND bpref_no = :cons;
opr varchar2(10) := 'DELETE';
TYPE tsch IS TABLE OF c2%ROWTYPE;
vtsch tsch;
cnt NUMBER := 0;
stime NUMBER;
etime NUMBER;
DURATION NUMBER;
rcount NUMBER;
errorsd PLS_INTEGER;
ecode NUMBER;
val1 VARCHAR2 (100);
val2 VARCHAR2 (100);
val3 VARCHAR2 (100);
val4 VARCHAR2 (100);
BEGIN
BEGIN
stime := DBMS_UTILITY.get_time ();
OPEN c2;
LOOP
FETCH c2
BULK COLLECT INTO vtsch LIMIT 1000;
IF vtsch.COUNT = 1000
THEN
cnt := cnt + 1;
END IF;
If opr = 'INSERT' Then
FORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
INSERT INTO dlul.ibs_pda_bills
VALUES vtsch (i);
Else
FORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
Delete from vw_ibs_pda_bills_x where bill_month = vtsch(i).bill_month;
End if;
EXIT WHEN c2%NOTFOUND;
END LOOP;
etime := DBMS_UTILITY.get_time ();
DURATION := ((etime - stime) / 100) / 60;
rcount :=
(cnt * 1000) + vtsch.COUNT - NVL (SQL%BULK_EXCEPTIONS.COUNT, 0);
If opr = 'INSERT' Then
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS', DURATION, rcount);
Else
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS-D', DURATION, rcount);
End if;
CLOSE c2;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
errorsd := SQL%BULK_EXCEPTIONS.COUNT;
IF errorsd > 0
THEN
FOR j IN 1 .. errorsd
LOOP
ecode := SQL%BULK_EXCEPTIONS (j).ERROR_CODE;
val1 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).sch_code;
val2 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bpref_no;
val3 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bill_month;
val4 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).service_code;
If opr = 'INSERT' Then
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'INSERT');
Else
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'DELETE');
End if;
END LOOP;
END IF;
END;
END pda_insert;the program want to do the delet option for all delete is not working. The program executed successful but the operation delete is not happening
how to solve this issue.
please help me
kanishNo error encountered in my log table
the new workaround you said, that is instead of for all , already i tried for i in 1.. to like
instead of forall delete i tried the following way
Declare
CURSOR c2 IS
SELECT *
FROM ibs_pda_bills_x@testarch1
WHERE bill_month <= '31-dec-2008'; -- AND bpref_no = :cons;
opr varchar2(10) := 'DELETE';
TYPE tsch IS TABLE OF c2%ROWTYPE;
vtsch tsch;
cnt NUMBER := 0;
stime NUMBER;
etime NUMBER;
DURATION NUMBER;
rcount NUMBER;
errorsd PLS_INTEGER;
ecode NUMBER;
val1 VARCHAR2 (100);
val2 VARCHAR2 (100);
val3 VARCHAR2 (100);
val4 VARCHAR2 (100);
BEGIN
BEGIN
stime := DBMS_UTILITY.get_time ();
OPEN c2;
LOOP
FETCH c2
BULK COLLECT INTO vtsch LIMIT 1000;
IF vtsch.COUNT = 1000
THEN
cnt := cnt + 1;
END IF;
If opr = 'INSERT' Then
FORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
INSERT INTO dlul.ibs_pda_bills
VALUES vtsch (i);
Else
/* fORALL i IN 1 .. vtsch.COUNT SAVE EXCEPTIONS
Delete from vw_ibs_pda_bills_x where to_char(bill_month,'dd-mm-rrrr') = to_char(vtsch (i).bill_month,'dd-mm-rrrr');*/
for i in 1..vtsch.count loop
delete ibs_pda_bills_x@testarch1 where to_char(bill_month,'dd-mm-rrrr') = to_char(vtsch (i).bill_month,'dd-mm-rrrr');
end loop;
End if;
EXIT WHEN c2%NOTFOUND;
END LOOP;
etime := DBMS_UTILITY.get_time ();
DURATION := ((etime - stime) / 100) / 60;
rcount :=
(cnt * 1000) + vtsch.COUNT - NVL (SQL%BULK_EXCEPTIONS.COUNT, 0);
If opr = 'INSERT' Then
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS', DURATION, rcount);
Else
INSERT INTO process_stage_log
VALUES (SYSDATE, 'IBS_PDA_BILLS-D', DURATION, rcount);
End if;
CLOSE c2;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
errorsd := SQL%BULK_EXCEPTIONS.COUNT;
IF errorsd > 0
THEN
FOR j IN 1 .. errorsd
LOOP
ecode := SQL%BULK_EXCEPTIONS (j).ERROR_CODE;
val1 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).sch_code;
val2 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bpref_no;
val3 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).bill_month;
val4 :=
vtsch (SQL%BULK_EXCEPTIONS (j).ERROR_INDEX).service_code;
If opr = 'INSERT' Then
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'INSERT');
Else
INSERT INTO process_error_log
VALUES (SYSDATE, ecode, 'IBS_PDA_BILLS', 'sch_code', val1,
'bpref_no', val2, 'bill_month', val3, 'service_code', val4,'DELETE');
End if;
END LOOP;
END IF;
END;
END pda_insert;i am receiving the following error
ORA-02055: distributed update operation failed; rollback required
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 77
ORA-06531: Reference to uninitialized collection
kanish -
Simple FORALL statement but runs very slow
Hi Guys,
I'm new to Oracle and I start to use it with .NET application. I have to collections that I want to pass as Associative arrays to PL/SQL procedure and want to update a table based on values on those collections but it runs very very slow 10 minutes for only 1000 record.
here is the code
.NET
OracleCommand cmd = con.CreateCommand();
cmd.CommandText = COMMAND_TEXT;
cmd.CommandType = CommandType.StoredProcedure;
var memberNoParam = new OracleParameter { ParameterName = PARAM_MEMBER_NO, OracleDbType = OracleDbType.Varchar2, Value = memberNoArray, CollectionType = OracleCollectionType.PLSQLAssociativeArray };
var statusParam = new OracleParameter { ParameterName = PARAM_STATUS, OracleDbType = OracleDbType.Int32, Value = statusArray, CollectionType = OracleCollectionType.PLSQLAssociativeArray };
var siteIDParam = new OracleParameter { ParameterName = PARAM_SITE_ID, OracleDbType = OracleDbType.Int32, Value = GlobalizationConfigurationSettings.Current.DefaultLocale.SiteId };
cmd.Parameters.Add(memberNoParam);
cmd.Parameters.Add(statusParam);
cmd.Parameters.Add(siteIDParam);
cmd.ExecuteNonQuery();
contextTransaction.Commit();
PL/SQL
PROCEDURE P_UPD_STATUS (
P_MEMBER_NO IN VARCHAR30_ARRAY,
P_STATUS IN INTEGER_ARRAY,
P_SITE_ID IN SITE.SITE_ID%TYPE)
IS
BEGIN
FORALL I IN VALUES OF P_MEMBER_NO
UPDATE DIRECT_DEBIT_MIGRATION_T
SET
STATUS = 1,
STATUS_DATE = SYSDATE,
LAST_UPD_BY = '13.10 SEPA Tool',
LAST_UPD_DATE = SYSDATE
WHERE SEPA_MIGRATION_ID = P_MEMBER_NO(I)
AND SITE_ID=P_SITE_ID;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('PKG_ALERT ERROR: P_UPD_STATUS : ' || SQLERRM );
RAISE_APPLICATION_ERROR (-20999, SQLERRM);
END P_UPD_STATUS;
I've been reading about FORALL from yesterday with no help. please adviseI'm new to Oracle and I start to use it with .NET application. I have to collections that I want to pass as Associative arrays to PL/SQL procedure and want to update a table based on values on those collections but it runs very very slow 10 minutes for only 1000 record.
If your array has 1000 records than this means that you do 1000 single updates - if those updates cannot benefit from a decent index access than this will be slow as hell. So as you've been told, check indexes, statistics and the performance of a single update.
And perhaps you could rewrite your query as
UPDATE DIRECT_DEBIT_MIGRATION_T
SET
STATUS = 1,
STATUS_DATE = SYSDATE,
LAST_UPD_BY = '13.10 SEPA Tool',
LAST_UPD_DATE = SYSDATE
WHERE SITE_ID=P_SITE_ID
AND SEPA_MIGRATION_ID IN (SELECT column_value from TABLE(P_MEMBER_NO));
which would be one update processing 1000 rows rather than 1000 updates processing 1 row each. -
Hi
I have this procedure in may oracle 9.2. but it show me this error message in the forall statement.-
Error: PLS-00382: wrong type in expression.
why ???
==============================0
PROCEDURE pr_com_upd_prim_carg
-- MODIFICATION HISTORY
-- Person Date Comments
-- diazh 22/09/06
v_mon_carg cargas_credito.mon_carg%TYPE;
v_fec_carg cargas_credito.fec_carg%TYPE;
v_num_line tmp_comi_liq.num_line%TYPE;
v_num_cont tmp_comi_liq.num_cont%TYPE;
v_cant_cuotas_perc comi_def_linea.cant_cuotas_perc%TYPE;
v_existe VARCHAR2 (1);
-- Declare program variables as shown above
CURSOR c_recarg
IS
SELECT --dl.num_line, dl.num_cont, dl.cant_cuotas_perc
FROM comi_def_linea dl
WHERE dl.cod_estado = 'APROB' AND dl.cod_clco = 'PREPA' AND dl.fec_prim_carga IS NULL;
type t_recarg is table of comi_def_linea%rowtype index by binary_integer;
v_recarg t_recarg;
BEGIN
p_usuario := p_user;
p_periodo := TO_CHAR (p_fec_ini, 'YYYYMM');
pr_inserta_ctrl (3, 'PR_COM_UPD_PRIM_CARG');
printlg ('PR_COM_UPD_PRIM_CARG... Iniciado ', v_logfile);
printlg ('PR_COM_UPD_PRIM_CARG... Iniciado conteo de registros en cargas_credito ',
v_logfile);
BEGIN
SELECT DISTINCT '1'
INTO v_existe
FROM cargas_credito
WHERE fec_carg > (p_fec_ini - (1 / (3600 * 24))) AND fec_carg < (p_fec_fin + 1);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
printlg ('PR_COM_UPD_PRIM_CARG(1): Error ' || SQLERRM, v_logfile);
END;
printlg ('PR_COM_UPD_PRIM_CARG... Finalizado conteo de registros en cargas_credito ',
v_logfile
OPEN c_recarg;
loop
FETCH c_recarg
bulk collect into v_recarg limit 500;
exit when c_recarg%notfound;
for i in v_recarg.first .. v_recarg.last loop
IF v_recarg(i).cant_cuotas_perc = 0
THEN
pr_retorna_prim_carga (v_recarg(i).num_line, v_recarg(i).num_cont, v_existe/*esta es una variable cualquiera*/, v_recag(i).fec_prim_carga, v_recarg(i).mto_prim_carga);
END IF;
end loop;
forall i in v_recarg.first .. v_recarg.last
update comi_def_linea
SET fec_prim_carga = v_recarg(i),
mto_prim_carga = v_recarg(i)
WHERE num_line = v_recarg(i) AND num_cont = v_recarg(i);
v_recarg.delete;
END LOOP;
CLOSE c_recarg;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
printlg ( 'PR_COM_UPD_PRIM_CARG(3): Error '
|| SQLERRM
|| ' '
|| 'procesando linea '
|| v_num_line
|| '-'
|| v_num_cont,
v_logfile
END; -- PR_COM_UPD_PRIM_CARGThe type is a row type so for update statement you have to refer to column.
v_recar(i).num_cont.
pl/sql table type(i).columname That wouldn't work either (at least in 9iR2):
DECLARE
TYPE emp_type IS TABLE OF emp%ROWTYPE
INDEX BY BINARY_INTEGER;
emp_tab emp_type;
BEGIN
FORALL i IN 1 .. emp_tab.LAST
UPDATE emp
SET sal = emp_tab (i).sal
WHERE empno = emp_tab (i).empno;
END;
Error at line 4
ORA-06550: line 9, column 20:
PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records
ORA-06550: line 9, column 20:
PLS-00382: expression is of wrong type
ORA-06550: line 10, column 22:
PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records
ORA-06550: line 10, column 22:
PLS-00382: expression is of wrong type
ORA-06550: line 9, column 20:
PL/SQL: ORA-22806: not an object or REF
ORA-06550: line 8, column 7:
PL/SQL: SQL StatemenMessage was edited by:
michaels -
Hi All,
I am using FORALL for inserting 40000 records from the file to the table. After reading data from the file it has been stored in type Table array, But while executing FORALL statement its giving ora-00600. error.
It is a memory error, some where I read to using LIMIT in fetch. But I am not using any fetch or Cursor. Can any body Help.
SKM
=================== ================= Package Code
create or replace package insertpackage as
TYPE tabSNO IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
TYPE tabSNO1 IS TABLE OF VARCHAR2(1) INDEX BY BINARY_INTEGER;
TYPE tabSDATE IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;
TYPE SNO IS TABLE OF NUMBER(5) INDEX BY BINARY_INTEGER;
procedure insertpro(snoArray IN SNO, sDate IN tabSDATE, sArray IN tabSNO, sArray1 IN tabSNO1);
end insertpackage;
create or replace package body insertpackage as
procedure insertpro(snoArray IN SNO, sDate IN tabSDATE, sArray IN tabSNO, sArray1 IN tabSNO1) is
begin
forall i in 1..sArray.last
insert into test(s_no, s_date, s_co, s_type)
values(snoArray(i), TO_DATE(sDate(i),'YYYY-MM-DD HH24.MI.SS'), sArray(i), sArray1(i));
end;
end insertpackage;
/Hi User,
The error
implementation restriction: cannot reference fields of BULK In-BIND table of recordsis because bulk bind cannot use table of composite types.
Please See the below,
http://dba-blog.blogspot.com/2005/08/using-of-bulk-collect-and-forall-for.html
And rewrite your code like this,
DECLARE
CURSOR EMP_CUR
IS
SELECT EMPNO, ENAME
FROM EMP;
TYPE TAB_EMP_EMPNO IS TABLE OF EMP.EMPNO%TYPE;
V_TAB_EMPNO TAB_EMP_EMPNO;
TYPE TAB_EMP_ENAME IS TABLE OF EMP.ENAME%TYPE;
V_TAB_ENAME TAB_EMP_ENAME;
BEGIN
OPEN EMP_CUR;
FETCH EMP_CUR BULK COLLECT INTO V_TAB_EMPNO, V_TAB_ENAME;
FORALL I IN V_TAB_EMPNO.FIRST .. V_TAB_EMPNO.LAST
INSERT INTO EMP_TEMP
(EMPNO, ENAME
VALUES (V_TAB_EMPNO (I), V_TAB_ENAME (I)
CLOSE EMP_CUR;
END;Thanks,
Shankar -
FORALL Exception handling problem
Hi All,
I have one doubt in forall exception handling. I have gone through the SAVE EXCEPTION for bulk collect but i have one more query
BEGIN
FORALL j IN l_tab.first .. l_tab.last
INSERT INTO exception_test
VALUES (l_tab(i));
EXCEPTION
END;
My requirement is when an exception occurs, i ant to print the values of the collection.
e.g. say l_tab (j).emp_number, l_tab (j).emp_id.
How is that possible?
Thanks
Samarth
Edited by: 950810 on Mar 12, 2013 7:28 PM>
I have one doubt in forall exception handling. I have gone through the SAVE EXCEPTION for bulk collect but i have one more query
BEGIN
FORALL j IN l_tab.first .. l_tab.last
INSERT INTO exception_test
VALUES (l_tab(i));
EXCEPTION
END;
My requirement is when an exception occurs, i ant to print the values of the collection.
e.g. say l_tab (j).emp_number, l_tab (j).emp_id.
How is that possible?
>
Post the code you are using. You didn't post the FORALL that is using SAVE EXCEPTIONS.
The SQL%BULK_EXCEPTIONS associative array that you get has the INDEX of the collection element that caused the exception.
So you need to use those indexes to index into the original collection to get whatever values are in it.
One index from the exception array is:
SQL%BULK_EXCEPTIONS(i).error_index So if your original collection is named 'myCollection' you would reference that collection value as:
myCollection(SQL%BULK_EXCEPTIONS(i).error_index); See 'Handling FORALL Exceptions (%BULK_EXCEPTIONS Attribute)' in the PL/SQL Language doc
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/tuning.htm#i49099
>
All exceptions raised during the execution are saved in the cursor attribute %BULK_EXCEPTIONS, which stores a collection of records. Each record has two fields:
%BULK_EXCEPTIONS(i).ERROR_INDEX holds the iteration of the FORALL statement during which the exception was raised.
%BULK_EXCEPTIONS(i).ERROR_CODE holds the corresponding Oracle Database error code.
The values stored by %BULK_EXCEPTIONS always refer to the most recently executed FORALL statement. The number of exceptions is saved in %BULK_EXCEPTIONS.COUNT. Its subscripts range from 1 to COUNT.
The individual error messages, or any substitution arguments, are not saved, but the error message text can looked up using ERROR_CODE with SQLERRM as shown in Example 12-9.
You might need to work backward to determine which collection element was used in the iteration that caused an exception. For example, if you use the INDICES OF clause to process a sparse collection, you must step through the elements one by one to find the one corresponding to %BULK_EXCEPTIONS(i).ERROR_INDEX. If you use the VALUES OF clause to process a subset of elements, you must find the element in the index collection whose subscript matches %BULK_EXCEPTIONS(i).ERROR_INDEX, and then use that element's value as the subscript to find the erroneous element in the original collection. -
TDE Issue with UPDATE/SELECT statement
We just implemented TDE on a table and now our import script is getting errors. The import script has not changed and has been running fine for over a year. The script failed right after applying TDE on the table.
Oracle 10g Release 2 on Solaris.
Here are the encrypted colums:
COLUMN_NAME ENCRYPTION_ALG SALT
PERSON_ID AES 192 bits key NO
PERSON_KEY AES 192 bits key NO
USERNAME AES 192 bits key NO
FIRST_NAME AES 192 bits key NO
MIDDLE_NAME AES 192 bits key NO
LAST_NAME AES 192 bits key NO
NICKNAME AES 192 bits key NO
EMAIL_ADDRESS AES 192 bits key NO
AKO_EMAIL AES 192 bits key NO
CREATION_DATE AES 192 bits key NO
Here is the UPDATE/SELECT statement that is failing:
UPDATE cslmo_framework.users a
SET ( person_id
, username
, first_name
, middle_name
, last_name
, suffix
, user_status_seq
= (
SELECT person_id
, username
, first_name
, middle_name
, last_name
, suffix
, user_status_seq
FROM cslmo.vw_import_employee i
WHERE i.person_key = a.person_key
WHERE EXISTS
SELECT 1
FROM cslmo.vw_import_employee i
WHERE i.person_key = a.person_key
AND ( NVL(a.person_id,0) <> NVL(i.person_id,0)
OR NVL(a.username,' ') <> NVL(i.username,' ')
OR NVL(a.first_name,' ') <> NVL(i.first_name,' ')
OR NVL(a.middle_name,' ') <> NVL(i.middle_name,' ')
OR NVL(a.last_name,' ') <> NVL(i.last_name,' ')
OR NVL(a.suffix,' ') <> NVL(i.suffix,' ')
OR NVL(a.user_status_seq,99) <> NVL(i.user_status_seq,99)
cslmo@awpswebj-dev> exec cslmo.pkg_acpers_import.p_users
Error importing USERS table.START p_users UPDATE
Error Message: ORA-01483: invalid length for DATE or NUMBER bind variableI rewrote the procedure using BULK COLLECT and a FORALL statement and that seems to work fine. Here is the new code:
declare
bulk_errors EXCEPTION ;
PRAGMA EXCEPTION_INIT(bulk_errors,-24381) ;
l_idx NUMBER ;
l_err_msg VARCHAR2(2000) ;
l_err_code NUMBER ;
l_update NUMBER := 0 ;
l_count NUMBER := 0 ;
TYPE person_key_tt
IS
TABLE OF cslmo_framework.users.person_key%TYPE
INDEX BY BINARY_INTEGER ;
arr_person_key person_key_tt ;
TYPE person_id_tt
IS
TABLE OF cslmo_framework.users.person_id%TYPE
INDEX BY BINARY_INTEGER ;
arr_person_id person_id_tt ;
TYPE username_tt
IS
TABLE OF cslmo_framework.users.username%TYPE
INDEX BY BINARY_INTEGER ;
arr_username username_tt ;
TYPE first_name_tt
IS
TABLE OF cslmo_framework.users.first_name%TYPE
INDEX BY BINARY_INTEGER ;
arr_first_name first_name_tt ;
TYPE middle_name_tt
IS
TABLE OF cslmo_framework.users.middle_name%TYPE
INDEX BY BINARY_INTEGER ;
arr_middle_name middle_name_tt ;
TYPE last_name_tt
IS
TABLE OF cslmo_framework.users.last_name%TYPE
INDEX BY BINARY_INTEGER ;
arr_last_name last_name_tt ;
TYPE suffix_tt
IS
TABLE OF cslmo_framework.users.suffix%TYPE
INDEX BY BINARY_INTEGER ;
arr_suffix suffix_tt ;
TYPE user_status_seq_tt
IS
TABLE OF cslmo_framework.users.user_status_seq%TYPE
INDEX BY BINARY_INTEGER ;
arr_user_status_seq user_status_seq_tt ;
CURSOR users_upd IS
SELECT i.person_key
,i.person_id
,i.username
,i.first_name
,i.middle_name
,i.last_name
,i.suffix
,i.user_status_seq
FROM cslmo.vw_import_employee i ,
cslmo_framework.users u
WHERE i.person_key = u.person_key ;
begin
OPEN users_upd ;
LOOP
FETCH users_upd
BULK
COLLECT
INTO arr_person_key
, arr_person_id
, arr_username
, arr_first_name
, arr_middle_name
, arr_last_name
, arr_suffix
, arr_user_status_seq
LIMIT 100 ;
FORALL idx IN 1 .. arr_person_key.COUNT
SAVE EXCEPTIONS
UPDATE cslmo_framework.users u
SET
person_id = arr_person_id(idx)
, username = arr_username(idx)
, first_name = arr_first_name(idx)
, middle_name = arr_middle_name(idx)
, last_name = arr_last_name(idx)
, suffix = arr_suffix(idx)
, user_status_seq = arr_user_status_seq(idx)
WHERE u.person_key = arr_person_key(idx)
AND
( NVL(u.person_id,0) != NVL(arr_person_id(idx),0)
OR
NVL(u.username,' ') != NVL(arr_username(idx),' ')
OR
NVL(u.first_name,' ') != NVL(arr_first_name(idx),' ')
OR
NVL(u.middle_name, ' ') != NVL(arr_middle_name(idx), ' ')
OR
NVL(u.last_name,' ') != NVL(arr_last_name(idx),' ')
OR
NVL(u.suffix,' ') != NVL(arr_suffix(idx),' ')
OR
NVL(u.user_status_seq,99) != NVL(arr_user_status_seq(idx),99)
l_count := arr_person_key.COUNT ;
l_update := l_update + l_count ;
EXIT WHEN users_upd%NOTFOUND ;
END LOOP ;
CLOSE users_upd ;
COMMIT ;
dbms_output.put_line('updated records: ' || l_update);
EXCEPTION
WHEN bulk_errors THEN
FOR i IN 1 .. sql%BULK_EXCEPTIONS.COUNT
LOOP
l_err_code := sql%BULK_EXCEPTIONS(i).error_code ;
l_err_msg := sqlerrm(-l_err_code) ;
l_idx := sql%BULK_EXCEPTIONS(i).error_index;
dbms_output.put_line('error code: ' || l_err_code);
dbms_output.put_line('error msg: ' || l_err_msg);
dbms_output.put_line('at index: ' || l_idx);
END LOOP ;
ROLLBACK;
RAISE;
end ;
cslmo@awpswebj-dev> @cslmo_users_update
updated records: 1274There are about 20 or so other procedure in the import script. I don't want to rewrite them.
Does anyone know why the UPDATE/SELECT is failing? I checked Metalink and could not find anything about this problem.This is now an Oracle bug, #9182070 on Metalink.
TDE (transparent data encryption) does not work when an update/select statement references a remote database.
Maybe you are looking for
-
Can't get Filevault to turn off
I can't get filevault to turn off. I go to system preferences and click turn off and it looks like its about to then its comes up wit a message saying cannot turn filevault off...error...then it says its going to stay on my home folder..I need to tur
-
Hi, we are using db partitioning (Daily partition, Range partition) for sub_eve (partitioned on timestamp field) table. the daily partition contains 173millians on rows daily 40gb. i want to create local indexes for on partitioned key field. 1 sugges
-
Can anyone tell me why my Safari crashes upon launch from the supplied crash log please? I tried deleting it with CleanMyMac and restoring from an earlier, working version. Tried deleting plist and extension files (along with a few others). I am unab
-
I did some web searching, but found nothing in recent history regarding the use of Flash or Flash Lite in Win CE 6.0. I have an application that will require between 50 and 100 embedded devices and I would like to have Flash be the user interface. Pl
-
Special Stock E not supported (check your entry) error in returns delivery
Dear friends, While we are doing the returns delivery, we are getting the error " Special Stock E not supported (check your entry) Message no. M7146 Diagnosis The specified objekt (Special Stock E) is not supported." This is an M.T.O scenario In the