Wednesday, October 08, 2008

PLS-00431: bulk SQL attributes must use a single index

Always check out the original article at http://www.oraclequirks.com for latest comments, fixes and updates.

PLS-00431: bulk SQL attributes must use a single index
ORA-06550: line 15, column 37:
PL/SQL: ORA-00904: : invalid identifier
If you got a message like this, perhaps you tried to execute or compile a
PL/SQL program containing a statement like the following:
DECLARE
TYPE NUM_TAB IS TABLE OF INTEGER INDEX BY PLS_INTEGER;

COLL_OF_FLAGGED NUM_TAB;
COLL_OF_ORDERS NUM_TAB;
COLL_OF_PARTS NUM_TAB;
BEGIN
...
FORALL x IN 1..COLL_OF_FLAGGED.COUNT
UPDATE order_parts
SET is_damaged = 'Y'
WHERE order_id = COLL_OF_ORDERS(COLL_OF_FLAGGED(x))
AND part_id = COLL_OF_PARTS(COLL_OF_FLAGGED(x));
...
END;
I highlighted in red color the cause of problem: nested collection indexes.
FORALL cannot cope with nested collection indexes on 10GR2 and earlier (on 11G i didn't tried yet), which means that you will need to rewrite the statement as a non-bulk UPDATE loop structure:
...
FOR x IN 1..COLL_OF_FLAGGED.COUNT
LOOP
UPDATE order_parts
SET is_damaged = 'Y'
WHERE order_id = COLL_OF_ORDERS(COLL_OF_FLAGGED(x))
AND part_id = COLL_OF_PARTS(COLL_OF_FLAGGED(x));
END LOOP;
...
or alternatively you might want to modify the table structure and "demote" the pair (order_id, part_id) to a simple unique constraint, while creating a single column primary key based on a sequence number, which would probably allow you to rewrite the statement above in the following way (assuming that the collection COLL_OF_FLAGGED contains the new primary key values):
...
FORALL x IN 1..COLL_OF_FLAGGED.COUNT
UPDATE order_parts
SET is_damaged = 'Y'
WHERE order_part_id = COLL_OF_FLAGGED(x);
...

See message translations for PLS-00431 and search additional resources.

1 comment:

Skipjacker said...

it also has problems with a "2 dimensional array" like this

TYPE record$t IS TABLE OF VARCHAR2( 200 )
INDEX BY PLS_INTEGER;

TYPE value$t IS TABLE OF record$t
INDEX BY PLS_INTEGER;

v_Change_Array$ value$t;


FORALL i IN v_Change_Array$.FIRST .. v_Change_Array$.LAST

INSERT INTO flat_temp
VALUES ( v_Change_Array$( i )( 1 ), ....

sorry for formatting.

yes you can!

Two great ways to help us out with a minimal effort. Click on the Google Plus +1 button above or...
We appreciate your support!

latest articles