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.

Similar Messages

  • BULK COLLECT and FORALL with dynamic INSERT.

    Hello,
    I want to apply BULK COLLECT and FORALL feature for a insert statement in my procedure for performance improvements as it has to insert a huge amount of data.
    But the problem is that the insert statement gets generated dynamically and even the table name is found at the run-time ... so i am not able to apply the performance tuning concepts.
    See below the code
    PROCEDURE STP_MES_INSERT_GLOBAL_TO_MAIN
      (P_IN_SRC_TABLE_NAME                  VARCHAR2 ,
      P_IN_TRG_TABLE_NAME                  VARCHAR2 ,
      P_IN_ED_TRIG_ALARM_ID                 NUMBER ,
      P_IN_ED_CATG_ID                 NUMBER ,
      P_IN_IS_PIECEID_ALARM IN CHAR,
      P_IN_IS_LAST_RECORD IN CHAR
    IS
          V_START_DATA_ID                 NUMBER;
          V_STOP_DATA_ID                   NUMBER;
          V_FROM_DATA_ID                   NUMBER;
          V_TO_DATA_ID                       NUMBER;
          V_MAX_REC_IN_LOOP              NUMBER := 30000;
          V_QRY1         VARCHAR2(32767);
    BEGIN
                EXECUTE IMMEDIATE 'SELECT MIN(ED_DATA_ID), MAX(ED_DATA_ID) FROM '|| P_IN_SRC_TABLE_NAME INTO V_START_DATA_ID , V_STOP_DATA_ID;
                --DBMS_OUTPUT.PUT_LINE('ORIGINAL START ID := '||V_START_DATA_ID ||' ORIGINAL  STOP ID := ' || V_STOP_DATA_ID);
                V_FROM_DATA_ID := V_START_DATA_ID ;
                IF (V_STOP_DATA_ID - V_START_DATA_ID ) > V_MAX_REC_IN_LOOP THEN
                        V_TO_DATA_ID := V_START_DATA_ID + V_MAX_REC_IN_LOOP;
                ELSE
                       V_TO_DATA_ID := V_STOP_DATA_ID;
                END IF;
              LOOP
                    BEGIN
                 LOOP      
                            V_QRY1 := ' INSERT INTO '||P_IN_TRG_TABLE_NAME||
                            ' SELECT * FROM '||P_IN_SRC_TABLE_NAME ||
                            ' WHERE ED_DATA_ID BETWEEN ' || V_FROM_DATA_ID ||' AND ' || V_TO_DATA_ID;
                    EXECUTE IMMEDIATE V_QRY1;
    commit;
                                     V_FROM_DATA_ID :=  V_TO_DATA_ID + 1;
                            IF  ( V_STOP_DATA_ID - V_TO_DATA_ID > V_MAX_REC_IN_LOOP ) THEN
                                  V_TO_DATA_ID := V_TO_DATA_ID + V_MAX_REC_IN_LOOP;
                            ELSE
                                  V_TO_DATA_ID := V_TO_DATA_ID + (V_STOP_DATA_ID - V_TO_DATA_ID);
                            END IF;
                    EXCEPTION
                             WHEN OTHERS THEN.............
    ....................so on Now you can observer here that P_IN_SRC_TABLE_NAME is the source table name which we get as a parameter at run-time. I have used 2 table in the insert statement P_IN_TRG_TABLE_NAME (in which i have to insert data) and P_IN_SRC_TABLE_NAME(from where i have to insert data)
      V_QRY1 := ' INSERT INTO '||P_IN_TRG_TABLE_NAME||
                            ' SELECT * FROM '||P_IN_SRC_TABLE_NAME ||
                            ' WHERE ED_DATA_ID BETWEEN ' || V_FROM_DATA_ID ||' AND ' || V_TO_DATA_ID;
                    EXECUTE IMMEDIATE V_QRY1;now when i appy the bulk collect and forall feature i am facing the out of scope problem....see the code below ...
    BEGIN
                EXECUTE IMMEDIATE 'SELECT MIN(ED_DATA_ID), MAX(ED_DATA_ID) FROM '|| P_IN_SRC_TABLE_NAME INTO V_START_DATA_ID , V_STOP_DATA_ID;
                --DBMS_OUTPUT.PUT_LINE('ORIGINAL START ID := '||V_START_DATA_ID ||' ORIGINAL  STOP ID := ' || V_STOP_DATA_ID);
                V_FROM_DATA_ID := V_START_DATA_ID ;
                IF (V_STOP_DATA_ID - V_START_DATA_ID ) > V_MAX_REC_IN_LOOP THEN
                        V_TO_DATA_ID := V_START_DATA_ID + V_MAX_REC_IN_LOOP;
                ELSE
                       V_TO_DATA_ID := V_STOP_DATA_ID;
                END IF;
              LOOP
                    DECLARE
                     TYPE TRG_TABLE_TYPE IS TABLE OF P_IN_SRC_TABLE_NAME%ROWTYPE;
                     V_TRG_TABLE_TYPE TRG_TABLE_TYPE;
                     CURSOR TRG_TAB_CUR IS
                     SELECT * FROM P_IN_SRC_TABLE_NAME
                     WHERE ED_DATA_ID BETWEEN V_FROM_DATA_ID AND V_TO_DATA_ID;
                     V_QRY1 varchar2(32767);
                    BEGIN
                    OPEN TRG_TAB_CUR;
                    LOOP
                    FETCH TRG_TAB_CUR BULK COLLECT INTO V_TRG_TABLE_TYPE LIMIT 30000;
                    FORALL I IN 1..V_TRG_TABLE_TYPE.COUNT
                    V_QRY1 := ' INSERT INTO '||P_IN_TRG_TABLE_NAME||' VALUES V_TRG_TABLE_TYPE(I);'
                    EXECUTE IMMEDIATE V_QRY1;
                    EXIT WHEN TRG_TAB_CUR%NOTFOUND;
                    END LOOP;
                    CLOSE TRG_TAB_CUR;
                            V_FROM_DATA_ID :=  V_TO_DATA_ID + 1;
                            IF  ( V_STOP_DATA_ID - V_TO_DATA_ID > V_MAX_REC_IN_LOOP ) THEN
                                  V_TO_DATA_ID := V_TO_DATA_ID + V_MAX_REC_IN_LOOP;
                            ELSE
                                  V_TO_DATA_ID := V_TO_DATA_ID + (V_STOP_DATA_ID - V_TO_DATA_ID);
                            END IF;
                    EXCEPTION
                             WHEN OTHERS THEN.........so on
    But the above code is not helping me ,  what i am doing wrong ??? how can i tune this dynamically generated statement to use bulk collect for better performace ......
    Thanks in Advance !!!!

    Hello,
    a table name cannot be bind as a parameter in SQL, this wont't compile:
    EXECUTE IMMEDIATE ' INSERT INTO :1 VALUES ......
    USING P_IN_TRG_TABLE_NAME ...but this should work:
    EXECUTE IMMEDIATE ' INSERT INTO ' || P_IN_TRG_TABLE_NAME || ' VALUES ......You cannot declare a type that is based on a table which name is in a variable.
    PL/SQL is stronly typed language, a type must be known at compile time, a code like this is not allowed:
    PROCEDURE xx( src_table_name varchar2 )
    DECLARE
       TYPE tab IS TABLE OF src_table_name%ROWTYPE;
      ...This can be done by creating one big dynamic SQL - see example below (tested on Oracle 10 XE - this is a slightly simplified version of your procedure):
    CREATE OR REPLACE
    PROCEDURE stp1(
      p_in_src_table_name                  VARCHAR2 ,
      p_in_trg_table_name                  VARCHAR2 ,
      v_from_data_id     NUMBER := 100,
      v_to_data_id       NUMBER := 100000
    IS
    BEGIN
      EXECUTE IMMEDIATE q'{
      DECLARE
         TYPE trg_table_type IS TABLE OF }' || p_in_src_table_name || q'{%ROWTYPE;
         V_TRG_TABLE_TYPE TRG_TABLE_TYPE;
         CURSOR TRG_TAB_CUR IS
         SELECT * FROM }' || p_in_src_table_name ||
         q'{ WHERE ED_DATA_ID BETWEEN :V_FROM_DATA_ID AND :V_TO_DATA_ID;
      BEGIN
          OPEN TRG_TAB_CUR;
          LOOP
                FETCH TRG_TAB_CUR BULK COLLECT INTO V_TRG_TABLE_TYPE LIMIT 30000;
                FORALL I IN 1 .. V_TRG_TABLE_TYPE.COUNT
                INSERT INTO }' || p_in_trg_table_name || q'{ VALUES V_TRG_TABLE_TYPE( I );
                EXIT WHEN TRG_TAB_CUR%NOTFOUND;
          END LOOP;
          CLOSE TRG_TAB_CUR;
      END; }'
      USING v_from_data_id, v_to_data_id;
      COMMIT;
    END;But this probably won't give any performace improvements. Bulk collect and forall can give performance improvements when there is a DML operation inside a loop,
    and this one single DML operates on only one record or relatively small number of records, and this DML is repeated many many times in the loop.
    I guess that your code is opposite to this - it contains insert statement that operates on many records (one single insert ~ 30000 records),
    and you are trying to replace it with bulk collect/forall - INSERT INTO ... SELECT FROM will almost alwayst be faster than bulk collect/forall.
    Look at simple test - below is a procedure that uses INSERT ... SELECT :
    CREATE OR REPLACE
    PROCEDURE stp(
      p_in_src_table_name                  VARCHAR2 ,
      p_in_trg_table_name                  VARCHAR2 ,
      v_from_data_id     NUMBER := 100,
      v_to_data_id       NUMBER := 100000
    IS
    V_QRY1 VARCHAR2(32767);
    BEGIN
          V_QRY1 := ' INSERT INTO '||   P_IN_TRG_TABLE_NAME ||
                    ' SELECT * FROM '|| P_IN_SRC_TABLE_NAME ||
                    ' WHERE ed_data_id BETWEEN :f AND :t ';
          EXECUTE IMMEDIATE V_QRY1
          USING V_FROM_DATA_ID, V_TO_DATA_ID;
          COMMIT;
    END;
    /and we can compare both procedures:
    SQL> CREATE TABLE test333
      2  AS SELECT level ed_data_id ,
      3            'XXX ' || LEVEL x,
      4            'YYY ' || 2 * LEVEL y
      5  FROM dual
      6  CONNECT BY LEVEL <= 1000000;
    Table created.
    SQL> CREATE TABLE test333_dst AS
      2  SELECT * FROM test333 WHERE 1 = 0;
    Table created.
    SQL> set timing on
    SQL> ed
    Wrote file afiedt.buf
      1  BEGIN
      2     FOR i IN 1 .. 100 LOOP
      3        stp1( 'test333', 'test333_dst', 1000, 31000 );
      4     END LOOP;
      5* END;
    SQL> /
    PL/SQL procedure successfully completed.
    Elapsed: 00:00:22.12
    SQL> ed
    Wrote file afiedt.buf
      1  BEGIN
      2     FOR i IN 1 .. 100 LOOP
      3        stp( 'test333', 'test333_dst', 1000, 31000 );
      4     END LOOP;
      5* END;
    SQL> /
    PL/SQL procedure successfully completed.
    Elapsed: 00:00:14.86without bulk collect ~ 15 sec.
    bulk collect version ~ 22 sec. .... 7 sec longer / 15 sec. = about 45% performance decrease.

  • How to use Bulk Collect and Forall

    Hi all,
    We are on Oracle 10g. I have a requirement to read from table A and then for each record in table A, find matching rows in table B and then write the identified information in table B to the target table (table C). In the past, I had used two ‘cursor for loops’ to achieve that. To make the new procedure, more efficient, I would like to learn to use ‘bulk collect’ and ‘forall’.
    Here is what I have so far:
    DECLARE
    TYPE employee_array IS TABLE OF EMPLOYEES%ROWTYPE;
    employee_data  employee_array;
    TYPE job_history_array IS TABLE OF JOB_HISTORY%ROWTYPE;
    Job_history_data   job_history_array;
    BatchSize CONSTANT POSITIVE := 5;
    -- Read from File A
    CURSOR c_get_employees IS
             SELECT  Employee_id,
                       first_name,
                       last_name,
                       hire_date,
                       job_id
              FROM EMPLOYEES;
    -- Read from File B based on employee ID in File A
    CURSOR c_get_job_history (p_employee_id number) IS
             select start_date,
                      end_date,
                      job_id,
                      department_id
             FROM JOB_HISTORY
             WHERE employee_id = p_employee_id;
    BEGIN
        OPEN c_get_employees;
        LOOP
            FETCH c_get_employees BULK COLLECT INTO employee_data.employee_id.LAST,
                                                                              employee_data.first_name.LAST,
                                                                              employee_data.last_name.LAST,
                                                                              employee_data.hire_date.LAST,
                                                                              employee_data.job_id.LAST
             LIMIT BatchSize;
            FORALL i in 1.. employee_data.COUNT
                    Open c_get_job_history (employee_data(i).employee_id);
                    FETCH c_get_job_history BULKCOLLECT INTO job_history_array LIMIT BatchSize;
                             FORALL k in 1.. Job_history_data.COUNT LOOP
                                            -- insert into FILE C
                                              INSERT INTO MY_TEST(employee_id, first_name, last_name, hire_date, job_id)
                                                                values (job_history_array(k).employee_id, job_history_array(k).first_name,
                                                                          job_history_array(k).last_name, job_history_array(k).hire_date,
                                                                          job_history_array(k).job_id);
                                             EXIT WHEN job_ history_data.count < BatchSize                        
                             END LOOP;                          
                             CLOSE c_get_job_history;                          
                     EXIT WHEN employee_data.COUNT < BatchSize;
           END LOOP;
            COMMIT;
            CLOSE c_get_employees;
    END;
                     When I run this script, I get
    [Error] Execution (47: 17): ORA-06550: line 47, column 17:
    PLS-00103: Encountered the symbol "OPEN" when expecting one of the following:
       . ( * @ % & - + / at mod remainder rem select update with
       <an exponent (**)> delete insert || execute multiset save
       merge
    ORA-06550: line 48, column 17:
    PLS-00103: Encountered the symbol "FETCH" when expecting one of the following:
       begin function package pragma procedure subtype type use
       <an identifier> <a double-quoted delimited-identifier> form
       current cursorWhat is the best way to code this? Once, I learn how to do this, I apply the knowledge to the real application in which file A would have around 200 rows and file B would have hundreds of thousands of rows.
    Thank you for your guidance,
    Seyed

    Hello BlueShadow,
    Following your advice, I modified a stored procedure that initially was using two cursor for loops to read from tables A and B to write to table C to use instead something like your suggestion listed below:
    INSERT INTO tableC
    SELECT …
    FROM tableA JOIN tableB on (join condition).I tried this change on a procedure writing to tableC with keys disabled. I will try this against the real table that has primary key and indexes and report the result later.
    Thank you very much,
    Seyed

  • 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.

  • About Collection and ForAll

    Dear Guru
    1) I have some documents about collection of 10g
    and example of Forall function.
    2) Question: I have procedure called Test_ps
    How to see the source code of the procedure
    A : User_source
    But i want to see how my parameter are there in procedure is there any option ?
    Advance Thanks..

    you can use DSEC <Procedure_Name> to see the list of arguments
    PRAZY@11gR1> create or replace procedure test_proc(a number,b number) is
      2  begin
      3  null;
      4  end;
      5  /
    Procedure created.
    Elapsed: 00:00:00.01
    PRAZY@11gR1> select text from user_source where name='TEST_PROC' order by line;
    TEXT
    procedure test_proc(a number,b number) is
    begin
    null;
    end;
    Elapsed: 00:00:00.01
    PRAZY@11gR1> desc test_proc;
    PROCEDURE test_proc
    Argument Name                  Type                    In/Out Default?
    A                              NUMBER                  IN
    B                              NUMBER                  INRegards,
    Prazy

  • JNDI bind/rebind and object state question

    Hi,
    I have an object that is part of an EAR application that is deployed into an app server. I load a Webapp that initializes an object and then binds it to an initial context under java:comp/env setting some initial state.
    However, when I access the object from an MDB as part of the EAR application, the state, when retrieved from the same context, was not retained. Here is the code I am using to bind the object to the context:
    if (!object.isRunning()) {
           System.out.println("Starting App...");
           object.start();
           try {
               getNamingContext().bind(object);
           } catch (Exception e) {
               System.out.println("Name bound already, rebinding...");
               try {
                   getNamingContext().rebind(object);
                   e.printStackTrace();
               } catch (Exception e1) {
                   e1.printStackTrace();
           System.out.println("Broker started...");
       }When I retrieve the object from the initial context as part of a message received within an MDB, the state is such that the object is always failing the .isRunning method test and subsequently throws an exception.
    What am I doing wrong? Is this related to the fact that possibly the WAR and the MDB create duplicate contexts when I expect there to be only one?
    Any insight is greatly appreciated.
    Thanks,
    John

    following procedure works fine for now, if there is any straight forward solutions,
    that will be helpful.
    1) Create the Subcontexts for each of the sub entries in the jndi name tree
    2) bind the object to the last entry in the tree.
    i.e if the jndi tree name is "one.two.three", and the bind object is Obj
    ctx = ctx.createSubcontext("one");
    ctx = ctx.createSubcontext("two");
    ctx = ctx.bind("three", obj);
    Thanks,
    Gangs.
    "Gangadhar" <[email protected]> wrote:
    >
    Hi,
    I am trying to bind the local object to the Weblogic JNDI, using the
    code below.
    It works fine if the bind name is a straight forward String(not a tree).
    It is
    throwing naming Exception when i am trying to bind into a new tree.
    Thanks,
    Gangs.
    //GETTING THE INITIAL CONTEXT:
    private Context getInitialContext() throws NamingException {
    Properties h = new Properties();
    h.put(Context.INITIAL_CONTEXT_FACTORY,
    "weblogic.jndi.WLInitialContextFactory");
    h.put(Context.SECURITY_PRINCIPAL, "user");
    h.put(Context.SECURITY_CREDENTIALS, "password");
    h.put(Context.PROVIDER_URL, url);
    return new InitialContext(h);
    } catch (NamingException ne) {
    log("We were unable to get a connection to the WebLogic server
    at "+url);
    log("Please make sure that the server is running.");
    throw ne;
    private registerObject()
    throws NamingException
    // Lookup the beans home using JNDI
    Context ctx = getInitialContext();
    try{
    //This binding works fine.
    String bname = "Ganga";
    ctx.bind("plainname", bname);
    //This one throws an Naming Exception..
    ctx.rebind("one.two.three", bname);
    } catch(javax.naming.NameAlreadyBoundException nlb){
    System.out.print(nlb.getMessage());
    System.exit(0);
    }catch(javax.naming.directory.InvalidAttributesException iae){
    System.out.print(iae.getMessage());
    System.exit(0);
    }catch(NamingException ne){
    System.out.print(ne.getMessage());
    System.exit(0);
    Exception msg is : Unable to resolve 'one.two.three' Resolved: '' Unresolved:'one'

  • BULK In-BIND and FORALL

    Hi All,
    Could someone help me in solving the error 'DML statement without BULK In-BIND cannot be used inside FORALL'. I am getting the error when running the following query.
    DECLARE
    v_seq_row_id NUMBER;
    TYPE ap_addr_tt IS TABLE OF IN_EIM_ADDR_PER.AP_ADDR%TYPE;
    TYPE ap_addr_name_tt IS TABLE OF IN_EIM_ADDR_PER.AP_ADDR_NAME%TYPE;
    TYPE ap_disc_flg_tt IS TABLE OF IN_EIM_ADDR_PER.AP_DISACLEANSE_FLG%TYPE;
    TYPE ap_name_lock_flg_tt IS TABLE OF IN_EIM_ADDR_PER.AP_NAME_LOCK_FLG%TYPE;
    TYPE ap_pre_flg_tt IS TABLE OF IN_EIM_ADDR_PER.AP_PREMISE_FLG%TYPE;
    coll_v_AP_ADDR ap_addr_tt;
    coll_v_AP_ADDR_NAME ap_addr_tt;
    coll_v_AP_DISACLEANSE_FLG ap_disc_flg_tt;
    coll_v_AP_NAME_LOCK_FLG ap_name_lock_flg_tt;
    coll_v_AP_PREMISE_FLG ap_pre_flg_tt;
    BEGIN
    SELECT
    DISTINCT(AP_ADDR),
    AP_ADDR_NAME,
    AP_DISACLEANSE_FLG,
    AP_NAME_LOCK_FLG,
    AP_PREMISE_FLG
    BULK COLLECT INTO
    coll_v_AP_ADDR,
    coll_v_AP_ADDR_NAME,
    coll_v_AP_DISACLEANSE_FLG,
    coll_v_AP_NAME_LOCK_FLG,
    coll_v_AP_PREMISE_FLG
    FROM
    IN_EIM_ADDR_PER;
    FORALL indx IN coll_v_AP_ADDR.FIRST.. coll_v_AP_ADDR.LAST
    SELECT seq_dm_row_id.NEXTVAL INTO v_seq_row_id FROM DUAL;
    /* for test only - more columns from will be included*/
    INSERT INTO SIEBEL.EIM_ADDR_PER
    (ROW_ID) VALUES (v_seq_row_id );
    END;
    I am new to collections and used cursors most of the time. It would be great if someone help me in solving this issue, which I am trying for looong time.
    Thanks.
    Yar

    Hi,
    I like to get clarified, Instead of the declaring individual variables can I try some like below. Could anyone advice me on this.
    TYPE in_tbl_col_type_rec IS RECORD (
    ap_addr_tt IN_EIM_ADDR_PER.AP_ADDR%TYPE,
    ap_addr_name_tt IN_EIM_ADDR_PER.AP_ADDR_NAME%TYPE,
    ap_disc_flg_tt IN_EIM_ADDR_PER.AP_DISACLEANSE_FLG%TYPE,
    ap_name_lock_flg_tt IN_EIM_ADDR_PER.AP_NAME_LOCK_FLG%TYPE,
    ap_pre_flg_tt IN_EIM_ADDR_PER.AP_PREMISE_FLG%TYPE);
    TYPE in_tbl_col_type_tbl IS TABLE OF in_tbl_col_type_rec
    INDEX BY PLS_INTEGER;
    v_in_tbl_col in_tbl_col_type_rec;
    And I am trying to use,
    FORALL indx IN v_in_tbl_col.FIRST.. v_in_tbl_col.LAST
    which is giving the error 'component 'FIRST' must be declared'.
    Thanks,
    Yar

  • Bind Variable in SELECT statement and get the value  in PL/SQL block

    Hi All,
    I would like  pass bind variable in SELECT statement and get the value of the column in Dynamic SQL
    Please seee below
    I want to get the below value
    Expected result:
    select  distinct empno ,pr.dept   from emp pr, dept ps where   ps.dept like '%IT'  and pr.empno =100
    100, HR
    select  distinct ename ,pr.dept   from emp pr, dept ps where   ps.dept like '%IT'  and pr.empno =100
    TEST, HR
    select  distinct loc ,pr.dept   from emp pr, dept ps where   ps.dept like '%IT'  and pr.empno =100
    NYC, HR
    Using the below block I am getting column names only not the value of the column. I need to pass that value(TEST,NYC..) into l_col_val variable
    Please suggest
    ----- TABLE LIST
    CREATE TABLE EMP(
    EMPNO NUMBER,
    ENAME VARCHAR2(255),
    DEPT VARCHAR2(255),
    LOC    VARCHAR2(255)
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (100,'TEST','HR','NYC');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (200,'TEST1','IT','NYC');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (300,'TEST2','MR','NYC');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (400,'TEST3','HR','DTR');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (500,'TEST4','HR','DAL');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (600,'TEST5','IT','ATL');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (700,'TEST6','IT','BOS');
    INSERT INTO EMP (EMPNO,ENAME,DEPT,LOC) VALUES (800,'TEST7','HR','NYC');
    COMMIT;
    CREATE TABLE COLUMNAMES(
    COLUMNAME VARCHAR2(255)
    INSERT INTO COLUMNAMES(COLUMNAME) VALUES ('EMPNO');
    INSERT INTO COLUMNAMES(COLUMNAME) VALUES ('ENAME');
    INSERT INTO COLUMNAMES(COLUMNAME) VALUES ('DEPT');
    INSERT INTO COLUMNAMES(COLUMNAME) VALUES ('LOC');
    COMMIT;
    CREATE TABLE DEPT(
    DEPT VARCHAR2(255),
    DNAME VARCHAR2(255)
    INSERT INTO DEPT(DEPT,DNAME) VALUES ('IT','INFORMATION TECH');
    INSERT INTO DEPT(DEPT,DNAME) VALUES ('HR','HUMAN RESOURCE');
    INSERT INTO DEPT(DEPT,DNAME) VALUES ('MR','MARKETING');
    INSERT INTO DEPT(DEPT,DNAME) VALUES ('IT','INFORMATION TECH');
    COMMIT;
    PL/SQL BLOCK
    DECLARE
      TYPE EMPCurTyp  IS REF CURSOR;
      v_EMP_cursor    EMPCurTyp;
      l_col_val           EMP.ENAME%type;
      l_ENAME_val       EMP.ENAME%type;
    l_col_ddl varchar2(4000);
    l_col_name varchar2(60);
    l_tab_name varchar2(60);
    l_empno number ;
    b_l_col_name VARCHAR2(255);
    b_l_empno NUMBER;
    begin
    for rec00 in (
    select EMPNO aa from  EMP
    loop
    l_empno := rec00.aa;
    for rec in (select COLUMNAME as column_name  from  columnames
    loop
    l_col_name := rec.column_name;
    begin
      l_col_val :=null;
       l_col_ddl := 'select  distinct :b_l_col_name ,pr.dept ' ||'  from emp pr, dept ps where   ps.dept like ''%IT'' '||' and pr.empno =:b_l_empno';
       dbms_output.put_line('DDL ...'||l_col_ddl);
       OPEN v_EMP_cursor FOR l_col_ddl USING l_col_name, l_empno;
    LOOP
        l_col_val :=null;
        FETCH v_EMP_cursor INTO l_col_val,l_ename_val;
        EXIT WHEN v_EMP_cursor%NOTFOUND;
          dbms_output.put_line('l_col_name='||l_col_name ||'  empno ='||l_empno);
       END LOOP;
    CLOSE v_EMP_cursor;
    END;
    END LOOP;
    END LOOP;
    END;

    user1758353 wrote:
    Thanks Billy, Would you be able to suggest any other faster method to load the data into table. Thanks,
    As Mark responded - it all depends on the actual data to load, structure and source/origin. On my busiest database, I am loading on average 30,000 rows every second from data in external files.
    However, the data structures are just that - structured. Logical.
    Having a data structure with 100's of fields (columns in a SQL table), raise all kinds of questions about how sane that structure is, and what impact it will have on a physical data model implementation.
    There is a gross misunderstanding by many when it comes to performance and scalability. The prime factor that determines performance is not how well you code, what tools/language you use, the h/w your c ode runs on, or anything like that. The prime factor that determines perform is the design of the data model - as it determines the complexity/ease to use the data model, and the amount of I/O (the slowest of all db operations) needed to effectively use the data model.

  • Reconciling garbage collection, heap overview, and object stats

    First, both the JRockit RuntimeAnalyzer and Console are great tools. We use
    them extensively so thank you.
    I'm trying to reconcile the numbers in these three tabs.
    1. How do I reconcile the Runtime Analyzer and Console output?
    - The Heap overview tab in our application profile shows Heap Overview as
    83% free.
    - However, the Garbage Collection tab of the profile and Console shows the
    application as oscillating between 50 Meg and 200 Meg of heap used. That's
    25% (50Meg/200Meg) to 100%(200Meg/200Meg) used. How do I interpret the 83%
    vs. the 100%?
    I don't believe the 83% free, but I'm skeptical that we consume 150Meg of
    memory in 50 seconds.
    2. How do I reconcile the Object stats with the Garbage collection?
    - Take the top heap user at end of recording, character buffer. It's 22.8%
    of heap using 6,328 KB. If the heap is actually only 34Meg ( 17% of 200Meg.
    I get the 17% from the 83% free), then 22.8% makes sense.
    - So what's in the 200Meg of heap?
    I sent this recording to the JRA team if you want to look at it.
    Thanks
    Jeff

    I've never heard it put that way. Very interesting.
    "Johan Walles" <johan@spamalamadingdong> wrote in message
    news:41bf0be3@mail...
    Note that the time it takes for the garbage collector to do its thing
    grows with the amount of live data.
    What the garbage collector really does is more like retaining the live
    data than disposing of the garbage.
    Regards //Johan
    Jeff wrote:
    Staffan,
    Thanks - you clearly answered my questions. Now the follow-on questions:
    1. Is there a way to get insight into what the 'dead' data is composed
    of?
    2. Is this pattern of consuming 3x the live data in about a minute
    'typical' or a disaster in the making?
    I'm trying to get a sense of what a reasonable target of 'dead' data is.
    The system processes about a meg of data per second, including database
    writes.
    Thanks
    Jeff
    "sla" <[email protected]> wrote in message
    news:33533893.1102952170368.JavaMail.root@jserv5...
    Hi Jeff,
    I'll try to answer the questions.
    1) The Heap overview in the application profile is a snapshot of the heap
    at the end of a garbage collection. At this time only live data is still
    on the heap. So it looks like you have 17% of the heap filled with live
    data (and some overhead as seen in the Heap overview).
    In the garbage collection tab you can see the heap usage oscillating
    between 35-40MB and 200MB. The lower value is right after a garbage
    collection and the higher value is right before a garbage collection. The
    garbage collector clears out about 160MB of "dead" data from the heap.
    This is the amount of temporary objects that you created during the
    garbage collection cycles.
    2) The Object statistics are also taken right after a garbage collection.
    At this time there is 34M of live data on the heap and of these about 22%
    is taken up by character arrays (not unusual).
    At this time the rest of the 200MB heap is empty. It's been cleared of
    all temporary objects and is ready for allocation of new objects.
    I hope this answered your questions.
    Regards,
    /Staffan

  • 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                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

  • 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 PM

    I 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

  • Bind Variables and Shared Component Report Query

    I have a query in a region report which I have replicated to a shared component report query.
    Both queries reference page items as bind variables in the where clause.
    The report region on screen shows the correct results but the report query shows "no data". This is the case when running "Test Query" and "Download XML data" from the shared component report query definition. If I hardcode the variable names I get rows returned, If I use bind variables - and specify the values for these variables I get no data. THe XML file contains the tags for each bind variable I have specified but has no data between the tags. I have Ticked the box to include application and session state but it appears that the bind variables are not being used.
    When I use my report query in the application (URL tied to a button) I get the same problem, the binds are not being passed to the report query.
    Can someone please clarify if this is a bug or not? And if not, how can I get it to work.
    I am using Apex 4.0.2
    Thanks
    Kathryn

    Hi
    To confirm, yes I selected the bind variables. I used these in the report layout, but the xml file has them as empty i.e.
    <P0_START_DATE><P0_START_DATE/> with nothing in between.
    IN the Test Query section, if I put real values in the boxes for the bind variables, I get no data found. If I hardcode the values into the query, I get the data.
    I've repeated the create report query many times and have created a report layout in RTF. I can use the layout with my region - in the print attributes and the layout works with the query but I need to create a PDF using 2 queries - ROWSET1 and ROWSET2. I can generate the XML but the values in the rows are all empty. When I use the layout with a report query instead of the region, I get no data even though I have used the same sql and have selected the bind variables. I was using variables from page items on page zero but have also tried using page items on the current page, the result is the same.
    I need to use a report query and a report layout as I need data from 2 queries in the PDF.
    I looked at your demo - what happens if you add a second sql query to the report query - is there any chance I can look at the back end (developer access?)
    Thanks for your input
    Kathryn

  • Can I put a SQL query into a bind variable and then use it to output report

    Hi,
    Can I put a SQL query into a bind variable and then use it to output report?
    I want to create a report and an item "text area" (say P1_TEXT) which can let user to input a SQL query(they are all technical users and knows SQL very well). Then, I use a bind variable (that text area) to store the SQL statement. Then, I add a submit button and I want to use the following to output the report:
    select * from (:P1_TEXT);
    Do you think it is possible to do that? Any known limitations for APEX in this area?
    Thanks a lot,
    Angela

    You can, but make sure it's what you really want to do. Make sure you are VERY familiar with SQL Injection. Most people who know what it is, go out of their way to prevent SQL Injection. You're going out of your way to allow it.
    You can try using &P1_TEXT. instead of bind variable syntax. Bind variables are one of the best ways to prevent SQL Injection, which is why it's not working for you.
    Once again, I strongly urge you to consider the implications of your app, but this suggestion should get it working.
    Tyler

  • Apex Collections and dates

    Apex Collections and Dates
    I made an earlier posting today on the forum titled “‘ORA-01861: literal does not match format string’ error after my hosting company upgraded to Apex 3.2.” The issue relates to Apex collections and dates. Prior to the hosting company upgrading Apex 3.2 from 3.1 all was working OK. It seemed a reasonable assumption that the issue relates to the upgrade to 3.2. Having tested the code against another Apex 3.2 installation I am satisfied that the issue is not with Apex 3.2. That said, I am still getting the issue on the hosting site.
    To demonstrate the issue to my hosting company and this forum, I put together a simple one page application that demonstrates the issue using the least amount of code.
    I created a page with an ‘On Load – Before header” process that sets up an Apex Collection with a single value of ’20-FEB-2009’ in the c001 element as follows:
    if apex_collection.collection_exists(p_collection_name=>'THEISSUE') then
    apex_collection.delete_collection(p_collection_name=>'THEISSUE');
    end if;
    apex_collection.create_collection(p_collection_name => 'THEISSUE');
    APEX_COLLECTION.ADD_MEMBER(
    p_collection_name => 'THEISSUE',
    p_c001 => '20-FEB-2009');
    I added an SQL REPORT region to the page which uses the Apex Collection as follows:
    select to_date(c001,'DD-MON-YYYY') testdate
    from apex_collections
    where collection_name='THEISSUE'
    and to_date('20-FEB-2009','DD-MON-YYYY')
    = to_date(c001,'DD-MON-YYYY')
    When the page is run I get the ‘ORA-01861: literal does not match format string’ error.
    If I remove the following from the SQL Report Region:
    and to_date('20-FEB-2009','DD-MON-YYYY')
    = to_date(c001,'DD-MON-YYYY')
    and run the page, the date is displayed OK, i.e., c001 is converted to a date OK. This made me wonder whether it does not like the line to_date('20-FEB-2009','DD-MON-YYYY')? So I changed the where code for the report to :
    and to_date(c001,'DD-MON-YYYY')
    = to_date(c001,'DD-MON-YYYY')
    i.e., convert c001 to a date and compare it to itself. The rationale being that if the c001 converts to a date OK, then comparing c001 converted to a date with itself should not give an error. It did it gave the same error ‘ORA-01861’
    It would seem on my hosting site since the upgrade, that Apex and Oracle have problems with Apex Collection elements being converted to dates as part of the where clause.
    Now my understating of Oracle Apex collections in simple terms is that all Apex collections are held in a single Oracle table managed by a series of Apex functions. Given that all Apex collections are in the same table, could the issue be with the Oracle database when it is creating its execution plan for the query? Could Oracle be including the value of c001 from other collections (i.e., when c001 is not in a date format ) in the initial stages of its execution plan?
    I hope the above make sense and thanks in advance.
    Ian

    Scott,
    I believe I have found the answer the statistics on WWV_FLOW_COLLECTIONS$ and WWV_FLOW_COLLECTION_MEMBERS$. are out of date and Oracle is doing a full table scan instead of using the indices to select only the c001 columns that belong to the given collection_id. If I change my simple example to store the date value in c050 it works ok. (In all probability this will be the only collection on the hosted database to use c050).
    I have asked the hosting company to gather stats on all the apex tables.
    Thanks for your help
    Ian

  • Using bulk collect and for all to solve a problem

    Hi All
    I have a following problem.
    Please forgive me if its a stupid question :-) im learning.
    1: Data in a staging table xx_staging_table
    2: two Target table t1, t2 where some columns from xx_staging_table are inserted into
    Some of the columns from the staging table data are checked for valid entries and then some columns from that row will be loaded into the two target tables.
    The two target tables use different set of columns from the staging table
    When I had a thousand records there was no problem with a direct insert but it seems we will now have half a million records.
    This has slowed down the process considerably.
    My question is
    Can I use the bulk collect and for all functionality to get specific columns from a staging table, then validate the row using those columns
    and then use a bulk insert to load the data into a specific table.?
    So code would be like
    get_staging_data cursor will have all the columns i need from the staging table
    cursor get_staging_data
    is select * from xx_staging_table (about 500000) records
    Use bulk collect to load about 10000 or so records into a plsql table
    and then do a bulk insert like this
    CREATE TABLE t1 AS SELECT * FROM all_objects WHERE 1 = 2;
    CREATE OR REPLACE PROCEDURE test_proc (p_array_size IN PLS_INTEGER DEFAULT 100)
    IS
    TYPE ARRAY IS TABLE OF all_objects%ROWTYPE;
    l_data ARRAY;
    CURSOR c IS SELECT * FROM all_objects;
    BEGIN
    OPEN c;
    LOOP
    FETCH c BULK COLLECT INTO l_data LIMIT p_array_size;
    FORALL i IN 1..l_data.COUNT
    INSERT INTO t1 VALUES l_data(i);
    EXIT WHEN c%NOTFOUND;
    END LOOP;
    CLOSE c;
    END test_proc;
    In the above example t1 and the cursor have the same number of columns
    In my case the columns in the cursor loop are a small subset of the columns of table t1
    so can i use a forall to load that subset into the table t1? How does that work?
    Thanks
    J

    user7348303 wrote:
    checking if the value is valid and theres also some conditional processing rules ( such as if the value is a certain value no inserts are needed)
    which are a little more complex than I can put in a simpleWell, if the processing is too complex (and conditional) to be done in SQL, then doing that in PL/SQL is justified... but will be slower as you are now introducing an additional layer. Data now needs to travel between the SQL layer and PL/SQL layer. This is slower.
    PL/SQL is inherently serialised - and this also effects performance and scalability. PL/SQL cannot be parallelised by Oracle in an automated fashion. SQL processes can.
    To put in in simple terms. You create PL/SQL procedure Foo that processes SQL cursor and you execute that proc. Oracle cannot run multiple parallel copies of Foo. It perhaps can parallelise that SQL cursor that Foo uses - but not Foo itself.
    However, if Foo is called by the SQL engine it can run in parallel - as the SQL process calling Foo is running in parallel. So if you make Foo a pipeline table function (written in PL/SQL), and you design and code it as a thread-safe/parallel enabled function, it can be callled and used and executed in parallel, by the SQL engine.
    So moving your PL/SQL code into a parallel enabled pipeline function written in PL/SQL, and using that function via parallel SQL, can increase performance over running that same basic PL/SQL processing as a serialised process.
    This is of course assuming that the processing that needs to be done using PL/SQL code, can be designed and coded for parallel processing in this fashion.

Maybe you are looking for