[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 401
  • Last Modified:

Processing within the FORALL Loop

Can I perform logic inside of a forall loop?
What I would like to do is increment a record id each time a row of data is inserted.

CREATE OR REPLACE PROCEDURE fast_proc (p_param IN VARCHAR2)
 IS

 TYPE ARRAY IS TABLE OF T1%ROWTYPE;
 l_data ARRAY;
 max_rec NUMBER;

 CURSOR c IS
 SELECT *
 FROM test_table t1
 inner join test_table_2 t2
 on t2.col1 = t1.col1;

 BEGIN
     max_rec := getMaxRecNumber; -- from function
     OPEN c;
     LOOP
     FETCH c BULK COLLECT INTO l_data LIMIT 100;
     
     FORALL i IN 1..l_data.COUNT
     
      -- Need to increment record number each time inserted
     
     -- Add max_rec
     max_rec  := max_rec + 1;

     INSERT INTO t1 VALUES l_data(i);

     EXIT WHEN c%NOTFOUND;
     END LOOP;
     CLOSE c;
 END fast_proc;
 /
0
cookiejar
Asked:
cookiejar
1 Solution
 
YZlatCommented:
are you getting any erros?
0
 
slightwv (䄆 Netminder) Commented:
I believe you can only perform a single DML statement in a FORALL.

I don't understand the need to increment maxvalue.  Would it not end up the same as getMaxRecNumber + l_data.COUNT?
0
 
slightwv (䄆 Netminder) Commented:
I also don't understand why you want to create in in-memory table and insert loop.

Why not just do it as a single insert?

INSERT INTO some_table
SELECT *
 FROM test_table t1
 inner join test_table_2 t2
 on t2.col1 = t1.col1;
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
MikeOM_DBACommented:
Did you try this?:
 . . .
FORALL i IN 1..l_data.COUNT
     INSERT INTO t1 VALUES l_data(i);

     -- Add max_rec
     max_rec  := max_rec + l_data.COUNT;

Open in new window

:p
0
 
Mark GeerlingsDatabase AdministratorCommented:
"Can I perform logic inside of a forall loop?"
Maybe.  But, do you even need to?

I agree with slightwv.  If you really want a "fast_proc" don't use a PL\SQL loop.  Just do a SQL insert based on a select, and use SQL%ROWCOUNT to get the number of records processed, like this:

CREATE OR REPLACE PROCEDURE fast_proc IS

 max_rec NUMBER;

 BEGIN
     max_rec := getMaxRecNumber; -- from function

     INSERT INTO t1
     SELECT *
     FROM test_table t1
     inner join test_table_2 t2
     on t2.col1 = t1.col1;
      
     max_rec  := max_rec + SQL%ROWCOUNT;

 END fast_proc;
 /

Note: the code you posted here did not use the input parameter at all, so I left it out.
0
 
cookiejarAuthor Commented:
I also don't understand why you want to create in in-memory table and insert loop.

So doing the following will be more efficient?

INSERT INTO t1
     SELECT *
     FROM test_table t1
     inner join test_table_2 t2
     on t2.col1 = t1.col1;
       
     max_rec  := max_rec + SQL%ROWCOUNT
0
 
slightwv (䄆 Netminder) Commented:
>>So doing the following will be more efficient?

Set up a quick test and try both methods.

Think about it.

Your way:
Create a cursor.
Load the entire result set into memory in a PL/SQL table.
Loop through it and insert the rows into another table.

or

Have the database create an implicit cursor and insert directly.

Which seems best?

Faster yet, use an APPEND hint on the insert.  Before you just make the jump to that you need to understand what that is doing.
0
 
PortletPaulCommented:
>>So doing the following will be more efficient?
yes, absolutely

a: "set operations" performed by internal dbms facilities -v- b: procedural code you build

a: will win
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now