Skip to Main Content
  • Questions
  • How to parse an array to update a table of records

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Sean.

Asked: June 05, 2017 - 9:18 pm UTC

Last updated: July 16, 2017 - 7:26 am UTC

Version: 12c

Viewed 1000+ times

You Asked

I am going to receive an array of account numbers from a .NET program, together with another array of statuses (1 for each account number) and I need to parse these arrays and update the status of those accounts in a table on the database:

Eg:

Inbound parameters: AccountArray = '1234','2345','3456','5678'
StatusArray = 'P','P','P','F'

I need to (for each of these account(s), update the account_history table:

UPDATE ACCOUNT_HISTORY
SET STATUS = <1st element in StatusArray >
WHERE ACCOUNT_NO = <first element in AccountArray>;

then

UPDATE ACCOUNT_HISTORY
SET STATUS = <2nd element in StatusArray >
WHERE ACCOUNT_NO = <2nd element in AccountArray>;

and so on, for all the elements in the arrays.

I may have at least 4, but I could have more than 4.

Is there a way to parse these values out in a loop and do it in one or two steps instead of using INSTR and SUBSTR?



and Connor said...

ODP.Net can 'converse' with arrays and bulk bind them.

Here's some examples from past Oracle Magazine articles

http://www.oracle.com/technetwork/issue-archive/2009/09-sep/o59odpnet-085168.html

http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o17odp-093600.html

Rating

  (1 rating)

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

Comments

BULK UPDATE into ORACLE Tables

Sean Liesenberg, July 10, 2017 - 6:41 pm UTC

Insead of an INSERT, I need an update but I need to check first what type of update. Can I include an IF check after the FORALL statement like so:
<BEGIN
forall i IN cyc_cycle_usage_no.FIRST..p_cycle_usage_no.LAST
IF p_process_cd(i) = 'F' THEN
UPDATE cycle_usage
SET cyc_process_cd = p_process_cd(i)
WHERE cyc_cycle_usage_no = p_cycle_usage_no(i)
AND cyc_acct_no = p_acct_no(i);
ELSE
UPDATE cycle_usage
SET cyc_process_cd = p_process_cd(i),
cyc_reported_dt = SYSDATE
WHERE cyc_cycle_usage_no = p_cycle_usage_no(i)
AND cyc_acct_no = p_acct_no(i);
end if;
END update_record;
</>

The problem is this throws an error and I'm not sure why.

Can you use an IF check like this inside the FORALL statement?

Thanks!

Connor McDonald
July 16, 2017 - 7:26 am UTC

No, but it can be part of the SQL predicate

SQL> create table t as select * from dba_objects where object_id is not null;

Table created.

SQL> alter table t add primary key ( object_id ) ;

Table altered.

SQL>
SQL> declare
  2    type rowlist is table of t%rowtype
  3      index by pls_integer;
  4
  5    r rowlist;
  6  begin
  7    select * bulk collect into r from t;
  8
  9    forall i in 1 .. r.count
 10      update t
 11      set owner = lower(owner)
 12      where object_id = r(i).object_id
 13      and   r(i).object_type = 'INDEX';
 14  end;
 15  /

PL/SQL procedure successfully completed.

SQL> select owner from t where object_type = 'INDEX' and rownum <= 5;

OWNER
------------------------------
sys
sys
sys
sys
sys

SQL> select owner from t where object_type != 'INDEX' and rownum <= 5;

OWNER
------------------------------
SYS
SYS
SYS
SYS
SYS


However, you might want to consider splitting the array into multiple arrays to ensure you are not wasting resources working through an array that is larger than it needs to be.