Bulk collect in pl/sql table SOLVED

Hi All,
TYPE r_nparameter IS RECORD( col1 tab.col1%TYPE, col2 tab.col2%TYPE);
TYPE t_no_seq IS TABLE OF r_nparameter INDEX BY BINARY_INTEGER;
the t_no_seq is not initialized.
My Question is
If we use t_itn_seq, in a BULK COLLECT operation in a select statement as...
SELECT col1, col2 BULK COLLECT INTO t_no_seq
and there is no record found for this query and exception is taken care of....thereafter we use this table in for loop as..
FOR icount IN 1..t_no_seq.COUNT
will this count raise any exception?
Best Regards.
Message was edited by:
user560602

It's not difficult to test this yourself...
SQL> declare
  2    type t_x is table of number index by binary_integer;
  3    v_x t_x;
  4  begin
  5    select rownum
  6    bulk collect into v_x
  7    from dual
  8    connect by rownum <= 10;
  9    for i in 1..v_x.count
10    loop
11      dbms_output.put_line(to_char(v_x(i)));
12    end loop;
13  end;
14  /
1
2
3
4
5
6
7
8
9
10
PL/SQL procedure successfully completed.
SQL> ed
Wrote file afiedt.buf
  1  declare
  2    type t_x is table of number index by binary_integer;
  3    v_x t_x;
  4  begin
  5    select rownum
  6    bulk collect into v_x
  7    from dual
  8    where 1=0;
  9    for i in 1..v_x.count
10    loop
11      dbms_output.put_line(to_char(v_x(i)));
12    end loop;
13* end;
SQL> /
PL/SQL procedure successfully completed.

Similar Messages

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

  • Bulk collect in pl/sql

    Hi there, need help, is it a right way of using bulk collect here?  As I could not get the correct result. 
    The problem is the 'where clause' is only taking 'SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE' column name
    to output but not for the rest of columns. The output given is only 3 records from  'SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE'. 
    In fact, other column names have records existed.  Please advise.  Regards, BE.
    FOR i in 1..l_flex_column_list.count LOOP
         dbms_output.put_line('SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name);
            BEGIN                   
            SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
                BULK COLLECT INTO l_flex_value_list  -- table collection
               FROM ego_value_set_values_v evsvv
                *WHERE evsvv.value_set_name= 'SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name;*
         EXCEPTION
           WHEN NO_DATA_FOUND THEN
              l_flex_value_list:=NULL;
           WHEN OTHERS THEN
              dbms_output.put_line('test ');
         END;
         END LOOP;
          dbms_output.put_line('');
          BEGIN
            FOR i in 1..l_flex_value_list.count LOOP
            dbms_output.put_line(l_flex_value_list(i).value_set_name ||' '||
                           l_flex_value_list(i).internal_name||' '||
                           l_flex_value_list(i).display_name);
            END LOOP;
          END;
    END;
    *Output*
    SEAEGO_CC_FAMILYMODEL_INFO_PRODUCT_TYPE
    SEAEGO_CC_FAMILYMODEL_INFO_INTERNAL_PRODUCT_NAME
    SEAEGO_CC_FAMILYMODEL_INFO_NUMBER_OF_HEADS
    SEAEGO_CC_FAMILYMODEL_INFO_NUMBER_OF_DISCS
    SEAEGO_CC_FAMILYMODEL_INFO_GENERATION
    SEAEGO_CC_FAMILYMODEL_INFO_DESIGN_APPLICATION
    SEAEGO_CC_FAMILYMODEL_INFO_FORM_FACTOR
    SEAEGO_CC_FAMILYMODEL_INFO_INTERFACE
    SEAEGO_CC_FAMILYMODEL_INFO_BASE_WARRANTY_MONTHS
    SEAEGO_CC_FAMILYMODEL_INFO_PHYSICAL_SECTOR_SIZE
    SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE
    _incorrect result_
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE NO ENCRYPTION No Encryption
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE BASE FDE Base
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE FIPS 140-2 FDE FIPS 140-2
    Query Statement for other columns
    SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
                FROM ego_value_set_values_v evsvv
            WHERE evsvv.value_set_name  = 'SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT'
    *Output*
    SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT     5MM     0.196 IN/5MM
    SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT     7MM     0.276 IN/7MM
    SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT     8MM     0.315 IN/8MM
    SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT     9.5MM     0.374 IN/9.5MM
    SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT     10.5MM     0.431 IN/10.5MM

    Hi there, the select statement below actually query record into 'l_flex_value_list' record variable by
    looping in different values e.g. SEAEGO_CC_FAMILYMODEL_INFO_BASE_WARRANTY_MONTHS,
    SEAEGO_CC_FAMILYMODEL_INFO_PHYSICAL_SECTOR_SIZE and SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE.
    But, my problem is the 'l_flex_value_list' is only storing the result for SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE, overwriting
    the values of SEAEGO_CC_FAMILYMODEL_INFO_BASE_WARRANTY_MONTHS and SEAEGO_CC_FAMILYMODEL_INFO_PHYSICAL_SECTOR_SIZE.
    What is the logic should be in this case?
       FOR i in 1..l_flex_column_list.count LOOP
      --   dbms_output.put_line('SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name);
        dbms_output.put_line(l_flex_column_list(i).column_name||' '||
                          l_flex_column_list(i).column_value);
            BEGIN                   
            SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
            BULK COLLECT INTO l_flex_value_list
            FROM ego_value_set_values_v evsvv
            WHERE evsvv.value_set_name= 'SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name;
          --  AND internal_name = l_flex_column_list(i).column_value;
         EXCEPTION
           WHEN NO_DATA_FOUND THEN
              l_flex_value_list:=NULL;
           WHEN OTHERS THEN
              dbms_output.put_line(' ');
         END;
         END LOOP;
    ------------------the PL/SQL -----------------------
    Declare
    l_query  VARCHAR2(2000);
    l_where VARCHAR2(2000);
    l_bind_var1      VARCHAR2(40);
    l_bind_var2      VARCHAR2(40);
    l_sql            NUMBER:=0;
    l_column_name    VARCHAR2(100);
    l_column_value   VARCHAR2(200);
    p_item_id NUMBER :=NULL;--931104 ;
    p_item_number       VARCHAR2(40):='9NH2D4-570';
    p_stmodel  VARCHAR2(40):='ST901603FGD1E1-RK';
    TYPE l_flex_column_rec IS RECORD
        column_name   varchar2(100),
        column_value  varchar2(100));
    TYPE l_flex_column_tab IS TABLE OF l_flex_column_rec;
    l_flex_column_list l_flex_column_tab;
    TYPE l_flex_value_rec IS RECORD
    ( value_set_name   fnd_flex_value_sets.flex_value_set_name%type,
       internal_name    fnd_flex_values.flex_value%type,
       display_name     fnd_flex_values_tl.description%type);
    TYPE l_flex_value_tab IS TABLE OF l_flex_value_rec;
    l_flex_value_list l_flex_value_tab;
    BEGIN
       IF p_stmodel is not null THEN
          IF p_item_number IS NULL AND p_item_id IS NULL THEN
           l_where  :='and st.stmodelnumber= :1 and sp.detailedproductname=''GENERIC''';
           l_bind_var1 := p_stmodel;
           l_sql := 1;
          ELSIF p_item_number IS NULL AND p_item_id IS NOT NULL THEN
           l_where  :='and st.stmodelnumber=:1 and sc.ccitemnumber = (select msi.segment1                       
                       from mtl_system_items msi                       
                       where msi.inventory_item_id = :2 and rownum=1)';
           l_bind_var1 := p_stmodel;
           l_bind_var2 := p_item_id;
           l_sql :=2;
          ELSE
           l_where  :='and st.stmodelnumber=:1 and sc.ccitemnumber = (select msi.segment1                      
                       from mtl_system_items msi                      
                       where msi.segment1=:2 and rownum=1)';
           l_bind_var1 := p_stmodel;
           l_bind_var2 := p_item_number;
           l_sql :=2;
          END IF; 
       ELSE
         IF p_item_id is null and p_item_number is not null THEN
                l_where := 'and sc.ccitemnumber = (select msi.segment1                      
                           from mtl_system_items msi                      
                           where msi.segment1=:1 and rownum=1)';
                l_bind_var1 :=  p_item_number;
                l_sql := 1;
            ELSIF p_item_id is NOT null and p_item_number is null THEN
                l_where := 'and sc.ccitemnumber = ( select msi.segment1                       
                            from mtl_system_items msi                       
                            where msi.inventory_item_id = :1 and rownum=1)';
                 l_bind_var1 := p_item_id;
                 l_sql := 1;
            ELSIF p_item_id is not null and p_item_number is not null THEN
                l_where :='and sc.ccitemnumber = (select msi.segment1                      
                           from mtl_system_items msi                      
                           where msi.inventory_item_id =:1                      
                           AND msi.segment1=:2 and rownum=1)';
                l_bind_var1 := p_item_id;
                l_bind_var2 := p_item_number;
                l_sql :=2;
            END IF;
        END IF;
    l_query :='select decode(rn,1,''PRODUCT_TYPE'',2,''INTERNAL_PRODUCT_NAME'',3,''NUMBER_OF_HEADS'',4,''NUMBER_OF_DISCS'',5,''GENERATION'',6,''DESIGN_APPLICATION'',
            7,''FORM_FACTOR'',8,''INTERFACE'',9,''BASE_WARRANTY_MONTHS'',10,''PHYSICAL_SECTOR_SIZE'',11,''MODEL_HEIGHT'',''ENCRYPTION_TYPE'') as column_name,
            decode(rn,1,st.producttype,2,sp.internalproductname,3,sp.numberofheads,4,sp.numberofdiscs,5,sp.generation,6,sp.designapplication,7,st.formfactor,
            8,st.interface,9,st.warrantymonths,10,st.physical_sector_size,11,st.modelheight,st.encryption_type) as column_value
            FROM  seaeng_productmodel sp , seaeng_stmodel st, seaeng_ccitemnumber sc , (select rownum rn from dual connect by rownum <=12)
            WHERE sc.productmodelnumber = sp.productmodelnumber
            AND sp.stmodelnumber = st.stmodelnumber ';
      IF l_sql = 1 THEN
          EXECUTE IMMEDIATE  l_query ||l_where
                             BULK COLLECT INTO l_flex_column_list
                             USING l_bind_var1 ;
                     --        dbms_output.put_line(l_query||l_where);
        ELSIF
             l_sql =2 THEN
            EXECUTE IMMEDIATE l_query || l_where
                             BULK COLLECT INTO l_flex_column_list
                             using l_bind_var1,l_bind_var2;
                  dbms_output.put_line(l_query||l_where);
        END IF;
       FOR i in 1..l_flex_column_list.count LOOP
      --   dbms_output.put_line('SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name);
        dbms_output.put_line(l_flex_column_list(i).column_name||' '||
                          l_flex_column_list(i).column_value);
            BEGIN                   
            SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
            BULK COLLECT INTO l_flex_value_list
            FROM ego_value_set_values_v evsvv
            WHERE evsvv.value_set_name= 'SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name;
          --  AND internal_name = l_flex_column_list(i).column_value;
         EXCEPTION
           WHEN NO_DATA_FOUND THEN
              l_flex_value_list:=NULL;
           WHEN OTHERS THEN
              dbms_output.put_line(' ');
         END;
         END LOOP;
          dbms_output.put_line('');
          BEGIN
            FOR i in 1..l_flex_value_list.count LOOP
            dbms_output.put_line(l_flex_value_list(i).value_set_name ||' '||
                           l_flex_value_list(i).internal_name||' '||
                           l_flex_value_list(i).display_name);
            END LOOP;
          END;
    END;
    -------OUTPUT
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE NO ENCRYPTION No Encryption
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE BASE FDE Base
    SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE FIPS 140-2 FDE FIPS 140-2

  • Related to PL/Sql table

    Is there is any way to use DML statement in PL/Sql table? Can I use select command on associative arrays or plsql tables.

    Check with Bulk collection concept ?
    I am not sure DML operation is not possible , because it is just ARRAY stores on your session only , You can delete one Index value or Add or Manuipulate , but no significance with Database.
    There are some properties with BULK COLLECTION on PL/SQL table that you can populate data to Database table

  • Bulk selection based on PL/SQL table

    Hi forum,
    I have a defined a pl/sql table named keys, contains 2 column keys(i).key and keys(i).desc.Now my requirement is to fetch the data based on from oracle table based on key strored in pl/sql table.
    I know that one option is to iterate through the table.like
    for i in 1..keys.count
    select value into x from <table> where key = keys(i).key
    Any options available to fetch the data in bulk by passing pl/sql table keys at once?
    Thanks in advance...
    Rgds,
    Aneesh A

    Something like this:
    SELECT empno, ename
      FROM emp
    WHERE deptno = 10
    ORDER BY deptno
         EMPNO ENAME
          7782 CLARK
          7839 KING
          7934 MILLER
    -- "record type"
    CREATE TYPE dept_type AS OBJECT (
       deptno NUMBER(2),
       dname  VARCHAR2(14),
       loc    VARCHAR2(13)
    -- nested table type
    CREATE TYPE dept_tab_type AS TABLE OF dept_type
    SET SERVEROUTPUT ON
    DECLARE
       l_dept_tab dept_tab_type;
    BEGIN
       SELECT dept_type (deptno, dname, loc)
         BULK COLLECT INTO l_dept_tab
         FROM dept
        WHERE deptno = 10;
       FOR rec IN (
         SELECT empno, ename
           FROM emp e,
                TABLE (l_dept_tab) d -- <=
          WHERE e.deptno = d.deptno
          ORDER BY empno)
       LOOP
          DBMS_OUTPUT.PUT_LINE (rec.empno || ' ' || rec.ename);
       END LOOP;
    END;
    7782 CLARK
    7839 KING
    7934 MILLERBut:
    1. you can't use associative array ("PL/SQL table" is Oracle 7 termin) - you must use nested table
    2. nested table type (and "record type") must be server defined
    3. (or 1.) using collection for million of records is not good approach - use SQL instead of PL/SQL!
    Regards,
    Zlatko Sirotic

  • Huge memory leaks in using PL/SQL tables and collections

    I have faced a very interesting problem recently.
    I use PL/SQL tables ( Type TTab is table of ... index by binary_integer; ) and collections ( Type TTab is table of ...; ) in my packages very widely. And have noticed avery strange thing Oracle does. It seems to me that there are memory leaks in PGA when I use PL/SQL tables or collections. Let me a little example.
    CREATE OR REPLACE PACKAGE rds_mdt_test IS
    TYPE TNumberList IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
    PROCEDURE test_plsql_table(cnt INTEGER);
    END rds_mdt_test;
    CREATE OR REPLACE PACKAGE BODY rds_mdt_test IS
    PROCEDURE test_plsql_table(cnt INTEGER) IS
    x TNumberList;
    BEGIN
    FOR indx IN 1 .. cnt LOOP
    x(indx) := indx;
    END LOOP;
    END;
    END rds_mdt_test;
    I run the following test code:
    BEGIN
    rds_mdt_test.test_plsql_table (1000000);
    END;
    and see that my session uses about 40M in PGA.
    If I repeat this example in the same session creating the PL/SQL table of smaller size, for instance:
    BEGIN
    rds_mdt_test.test_plsql_table (1);
    END;
    I see again that the size of used memory in PGA by my session was not decreased and still be the same.
    The same result I get if I use not PL/SQL tables, but collections or varrays.
    I have tried some techniques to make Oracle to free the memory, for instance to rewrite my procedure in the following ways:
    PROCEDURE test_plsql_table(cnt INTEGER) IS
    x TNumberList;
    BEGIN
    FOR indx IN 1 .. cnt LOOP
    x(indx) := indx;
    END LOOP;
    x.DELETE;
    END;
    or
    PROCEDURE test_plsql_table(cnt INTEGER) IS
    x TNumberList;
    BEGIN
    FOR indx IN 1 .. cnt LOOP
    x(indx) := indx;
    END LOOP;
    FOR indx in 1 .. cnt LOOP
    x.DELETE(indx);
    END LOOP;
    END;
    or
    PROCEDURE test_plsql_table(cnt INTEGER) IS
    x TNumberList;
    empty TNumberList;
    BEGIN
    FOR indx IN 1 .. cnt LOOP
    x(indx) := indx;
    END LOOP;
    x := empty;
    END;
    and so on, but result was the same.
    This is a huge problem for me as I have to manipulate collections and PL/SQL tables of very big size (from dozens of thousand of rows to millions or rows) and just a few sessions running my procedure may cause server's fall due to memory lack.
    I can not understand what Oracle reseveres such much memory for (I use local variables) -- is it a bug or a feature?
    I will be appreciated for any help.
    I use Oracle9.2.0.1.0 server under Windows2000.
    Thank you in advance.
    Dmitriy.

    Thank you, William!
    Your advice about using DBMS_SESSION.FREE_UNUSED_USER_MEMORY was very useful. Indeed it is the tool I was looking for.
    Now I write my code like this
    declare
    type TTab is table of ... index binary_integer;
    res TTab;
    empty_tab TTab;
    begin
    res(1) := ...;
    res := empty_tab;
    DBMS_SESSION.FREE_UNUSED_USER_MEMORY;
    end;
    I use construction "res := empty_tab;" to mark all memory allocated to PL/SQL table as unused according to Tom Kyte's advices. And I could live a hapy life if everything were so easy. Unfortunately, some tests I have done showed that there are some troubles in cleaning complex nested PL/SQL tables indexed by VARCHAR2 which I use in my current project.
    Let me another example.
    CREATE OR REPLACE PACKAGE rds_mdt_test IS
    TYPE TTab0 IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
    TYPE TRec1 IS RECORD(
    NAME VARCHAR2(4000),
    rows TTab0);
    TYPE TTab1 IS TABLE OF TRec1 INDEX BY BINARY_INTEGER;
    TYPE TRec2 IS RECORD(
    NAME VARCHAR2(4000),
    rows TTab1);
    TYPE TTab2 IS TABLE OF TRec2 INDEX BY BINARY_INTEGER;
    TYPE TStrTab IS TABLE OF NUMBER INDEX BY VARCHAR2(256);
    PROCEDURE test_plsql_table(cnt INTEGER);
    PROCEDURE test_str_tab(cnt INTEGER);
    x TTab2;
    empty_tab2 TTab2;
    empty_tab1 TTab1;
    empty_tab0 TTab0;
    str_tab TStrTab;
    empty_str_tab TStrTab;
    END rds_mdt_test;
    CREATE OR REPLACE PACKAGE BODY rds_mdt_test IS
    PROCEDURE test_plsql_table(cnt INTEGER) IS
    BEGIN
    FOR indx1 IN 1 .. cnt LOOP
    FOR indx2 IN 1 .. cnt LOOP
    FOR indx3 IN 1 .. cnt LOOP
    x(indx1) .rows(indx2) .rows(indx3) := indx1;
    END LOOP;
    END LOOP;
    END LOOP;
    x := empty_tab2;
    dbms_session.free_unused_user_memory;
    END;
    PROCEDURE test_str_tab(cnt INTEGER) IS
    BEGIN
    FOR indx IN 1 .. cnt LOOP
    str_tab(indx) := indx;
    END LOOP;
    str_tab := empty_str_tab;
    dbms_session.free_unused_user_memory;
    END;
    END rds_mdt_test;
    1. Running the script
    BEGIN
    rds_mdt_test.test_plsql_table ( 100 );
    END;
    I see that usage of PGA memory in my session is close to zero. So, I can judge that nested PL/SQL table indexed by BINARY_INTEGER and the memory allocated to it were cleaned successfully.
    2. Running the script
    BEGIN
    rds_mdt_test.test_str_tab ( 1000000 );
    END;
    I can see that plain PL/SQL table indexed by VARCHAR2 and memory allocated to it were cleaned also.
    3. Changing the package's type
    TYPE TTab2 IS TABLE OF TRec2 INDEX BY VARCHAR2(256);
    and running the script
    BEGIN
    rds_mdt_test.test_plsql_table ( 100 );
    END;
    I see that my session uses about 62M in PGA. If I run this script twice, the memory usage is doubled and so on.
    The same result I get if I rewrite not highest, but middle PL/SQL type:
    TYPE TTab1 IS TABLE OF TRec1 INDEX BY VARCHAR2(256);
    And only if I change the third, most nested type:
    TYPE TTab0 IS TABLE OF NUMBER INDEX BY VARCHAR2(256);
    I get the desired result -- all memory was returned to OS.
    So, as far as I can judge, in some cases Oracle does not clean complex PL/SQL tables indexed by VARCHAR2.
    Is it true or not? Perhaps there are some features in using such way indexed tables?

  • Issue with Anlytical Functions,Ref Cusor and Bulk Collect

    Hi All
    pls go through the following code
    declare
    type salt is table of emp.sal%type index by binary_integer;
    st salt;
    type refc is ref cursor;
    rc refc;
    begin
    open rc for 'select max(sal) over (Partition by deptno) as Sal from emp';
    fetch rc bulk collect into st;
    close rc;
    for i in st.first..st.last loop
    dbms_output.put_LINE(st(i));
    end loop;
    end;
    When execute above code following error come :
    declare
    ERROR at line 1:
    ORA-01001: invalid cursor
    ORA-06512: at line 8
    since Anlytical functions are not supported at pl/sql,i used the ref cursor,but these record are not allowed to collect in pl/sql table.
    pls can one send a work around.
    to insert recs into pl/sql table from anlytical function.
    Thanks for Reading the Request
    Raj Ganga
    mail : [email protected]

    Just ran it exactly as it is. It works.
    I am on 9i which version are you using..
    SQL> declare
    2 type salt is table of emp.sal%type index by binary_integer;
    3 st salt;
    4 type refc is ref cursor;
    5 rc refc;
    6 begin
    7 open rc for 'select max(sal) over (Partition by deptno) as Sal from emp';
    8 fetch rc bulk collect into st;
    9 close rc;
    10 for i in st.first..st.last loop
    11 dbms_output.put_LINE(st(i));
    12 end loop;
    13 end;
    14 /
    PL/SQL procedure successfully completed.
    SQL> set serveroutput on
    SQL> /
    5000
    5000
    5000
    3000
    3000
    3000
    3000
    3000
    2850
    2850
    2850
    2850
    2850
    2850
    PL/SQL procedure successfully completed.

  • Trouble with Bulk Collect to Ref cursor

    I'm trying to open a ref cursor to a dynamic query, and the fetch the cursor (BULK COLLECT)to the table type variable.But I keep getting the compilation error as 'PLS-00597: expression 'EMP_RESULTSET' in the INTO list is of wrong type'
    But when I use a simple select from a table and Bulk Collect directly to the table type variable it works. But that is not what I want.
    Can someone tell me where I have gone wrong in this stored proc I have listed below.
    your help will be highly appreciated.
    PROCEDURE SP_TEST_EMP_TABLE_TYPE (
          p_resultset OUT result_cursor          -- ref cursor as out parameter
       AS
        TYPE TYPE_REC_EMP is RECORD(EMPNO EMPLOYEE.EMPNO%TYPE, JOIN_DATE EMPLOYEE.JOIN_DATE%TYPE, SALARY EMPLOYEE.SALARY%TYPE); -- declare record type
        TYPE TYPE_TAB_EMP IS TABLE OF TYPE_REC_EMP;    -- declare table type
        EMP_RESULTSET TYPE_TAB_EMP; -- declare variable of type type_calendar_avail_resultset  
        SQUERY VARCHAR2(32000):='';
       BEGIN
        SQUERY:='SELECT EMPNO,JOIN_DATE,SALARY FROM EMPLOYEE WHERE EMPNO= 1001 AND JOIN_DATE=''20070530'' ';
        --select EMPNO,JOIN_DATE,SALARY BULK COLLECT INTO EMP_RESULTSET from  EMPLOYEE WHERE EMPNO=1001 AND JOIN_DATE='20070525';
        OPEN p_resultset FOR SQUERY;
          FETCH p_resultset BULK COLLECT INTO EMP_RESULTSET;
      EXCEPTION
          WHEN NO_DATA_FOUND
          THEN
             NULL;
          WHEN OTHERS
          THEN
             DBMS_OUTPUT.put_line (SQLERRM (SQLCODE));   
       END SP_TEST_EMP_TABLE_TYPE ;

    > i) I use a ref cursor to return back to the java
    front end, so I had to use a ref cursor.
    What is a ref cursor? It is not a data set. It is a pointer to a "SQL program". This program is created by the SQL Engine and the CBO that parses the SQL source code and determine an execution plan to get to the requested rows.
    When the client fetches from a (ref) cursor, the client is running this program and it find and returns the next row.
    There is no such thing as a physical result set for a cursor - no "copy" of the rows found for the source code SQL is made as a result set.
    > ii) I also use a dynamic sql, but I was thinking it
    wasn't useful for this posting, so tried to write a
    simple sql
    What is dynamic SQL? SQL where object names (e.g name of the table) is only known at run-time. Or where the filter (e.g. WHERE conditions) can only be determined at run time.
    If these are known, the SQL is static SQL.
    For both static and dynamic SQL, bind variables are critical. It is the biggest performance mistake (in Oracle) to hardcode values and literals into a SQL.
    > ii) I use a Bulk Collect to the table type
    collection, since I use a loop, for which I had to
    collect the results from each loop and finally send
    the resultset thru the ref cursor.
    Impossible. Nor does it make any sense. As stated, a ref cursor is a program and not a result set.
    What you intend to do is run a SQL against data. Copy this data into private/local PL/SQL memory. Construct another SQL against this data - which means that it needs to be shipped back to the SQL engine as it cannot use/read local PL/SQL memory structures. And the pass that SQL cursor to the client.
    What for?
    > I had earlier used the logic to for this using a
    temporary table, which works perfectly fine, but our
    DBA says we should avoid temporary tables since it
    makes additional read/write to the disk. This is the
    reason I'm using table type collection here.
    Your DBA is correct. One should so a single pass through a data set. Which is why simply passing a ref cursor for a SQL statement to the client is the simplest.
    It makes no sense copying SQL data into a collection and then copying that back into the SQL engine in order to throw a ref cursor around it.
    Basic client-server fundamentals.
    And why RTFM the Oracle manuals I've indicated is important. You need to understand the memory and processing architectures in Oracle in order to make an informed and correct decision.

  • (How) Can a SP call the Function which has BULK COLLECT return?

    I have a function using BULL COLLECT to put (XML data) many line into a table type record. (I had this as a function because it's gong to call many times).
    From one SP program, I will need to call it to get converted XML data info, how should i call it? If it's single line return, I could use
    my_result := get_tbl_xml(p_xml);
    but when it's table type, even I defined it, it still get error. Here is the program:
    Declare (at package spec)
    TYPE OrderDtl_Tab IS TABLE OF xxx%ROWTYPE INDEX BY BINARY_INTEGER;
    in_OrderDtlTab OrderDtl_Tab;
    FUNCTION get_tbl_xml (p_xml IN CLOB ) RETURN OrderDtl_Tab IS
    BEGIN
    SELECT extractvalue(VALUE(x), '/xxxx/xxxx') AS xxxx BULK COLLECT
    INTO in_OrderDtlTab
    FROM TABLE(xmlsequence(extract(xmltype(p_xml), '/Order/Lines/*'))) x;
    RETURN in_OrderDtlTab;
    END;
    PROCEDURE SAVE_A (p_xml IN CLOB )
    BEGIN
    --- how to call get_tbl_xml to get result, so I will be able to insert into DB table
    in_OrderDtlTab := get_tbl_xml(p_xml);
    END;
    --------------------------------------------------------------------------------------------------------------------

    May be this is better
    FUNCTION get_tbl_xml (p_xml IN CLOB ) RETURN OrderDtl_Tab IS
    BEGIN
    SELECT extractvalue(VALUE(x), '/xxxx/xxxx') AS xxxx BULK COLLECT
    INTO in_OrderDtlTab
    FROM TABLE(xmlsequence(extract(xmltype(p_xml), '/Order/Lines/*'))) x;
    RETURN in_OrderDtlTab;
    END;
    PROCEDURE SAVE_A (p_xml IN CLOB )
    yourrow your_table%rowtype;
    BEGIN
    --- how to call get_tbl_xml to get result, so I will be able to insert into DB table
    in_OrderDtlTab := get_tbl_xml(p_xml);
    FORALL myrowtype
    IN in_OrderDtlTab .FIRST .. in_OrderDtlTab .LAST
    INSERT INTO Your_table
    VALUES in_OrderDtlTab(yourrow);
    END;
    END;

  • How do I speed up this bulk collect

    Edited... Sorry for the wasted post...

    As soon as I posted this I figured out the problem so I removed the post. The problem was in the select section in the get_segment_length function and had nothing to do with the table() functions... After re-writing that this select actually works fast now...
          -- Join everything back together using the reduced segements tab.
          select sms.eval_rec(
            accd.accident_id,
            accd.accd_dte,
            accd.accd_catg,
            accd.accd_catg_description,
            accd.accd_rt_seq_num,
            accd.dmv_accd_clsf,
            sms.pa_pies_equations.get_segment_length(r_beg.rt_num, r_beg.rt_seq_num, r_end.rt_seq_num),
            r_beg.segment_region,
            r_beg.route_refmkr_id,
            r_end.route_refmkr_id,
            r_beg.refmkr,
            r_beg.rt_seq_num,
            r_end.refmkr,
            r_end.rt_seq_num,
            s.rt_num,
            p.construction_start_date,
            p.construction_end_date,
            p.investigation_id,
            p.maj_proj_num,
            p.proj_legacy_id,
            s.euac,
            s.est_severe_accident_reduction,
            s.est_total_accident_reduction,
            s.pseudo_segment_id)
          BULK COLLECT INTO v_final_tab
          from table(v_proj_tab) p, table(v_begin_route_tab) r_beg, table(v_end_route_tab) r_end, table(v_accd_tab) accd, table(v_segment_tab_reduced) s
          where ((p.investigation_id = s.investigation_id) or (p.investigation_id is null and s.investigation_id is null))
            and ((p.maj_proj_num     = s.maj_proj_num)     or (p.maj_proj_num     is null and s.maj_proj_num     is null))
            and ((p.proj_legacy_id   = s.proj_legacy_id)   or (p.proj_legacy_id   is null and s.proj_legacy_id   is null))
            and s.rt_num                        = r_beg.rt_num
            and s.begin_rt_seq_num              = r_beg.rt_seq_num
            and s.rt_num                        = r_end.rt_num
            and s.end_rt_seq_num                = r_end.rt_seq_num
            and s.rt_num                        = accd.rt_num
            and (accd.accd_rt_seq_num between r_beg.rt_seq_num and r_end.rt_seq_num or
                 accd.accd_rt_seq_num between r_end.rt_seq_num and r_beg.rt_seq_num);

  • Initialize  Pl/sql table values

    Hi,
    Can anyone tell me how the Initialize the values in a pl/sql tables. I want an Example.
    Cheers
    Nirmal

    > 1.Arrays are fixed with lower and upper bound, but PL/SQL tables are unbounded.
    Ever heard of dynamic arrays? (http://en.wikipedia.org/wiki/Dynamic_array)
    > 2.Arrays must be dense, which means index numbers must be consecutive (1,2,3,4…),
    but PL/SQL tables do not.
    You are confusing arrays with associative arrays. Subscripting an array is done with a numeric index value. An associative array is where the subscript is a key (the name for a name-value pair) and not a numeric index.
    See http://en.wikipedia.org/wiki/Arrays and http://en.wikipedia.org/wiki/Associative_array for details and definitions.
    So-called PL/SQL "tables" (table of <something> indexed by varchar2) are nothing but an associative array. That is the correct term.
    A "collection" is different in that it is a dynamic array of objects and is subscripted using an index.
    Calling either these a table in PL/SQL, often lead the programmer to believe that this similar is in nature to a SQL table - and then they attempt to treat an associative array or collection like a SQL table with all kinds of negative consequences ito programming design, memory usage, scalability and performance.
    IMO, whoever invented the term "PL/SQL table" is an idiot. It is utterly misleading in the context of using Oracle correctly.

  • Generic bulk collect function

    I've ran into a scenario in Forms (10g) where some of the embedded plsql could benefit from the use of Bulk Collects. Now, as I've just found out, Forms doesn't like Bulks in it's embedded code, returns a 'feature not supported in client...' error.
    I attempted to write a function in the db (10g), to be called from the Form, accept a ref cursor parameter, Fetch the cursor contents using bulk into an array, then return the filled array to the Form. (It may not be performant either, but I'll never know because I didn't get it working.)
    However, fatally, I can't create a record array in the function without knowing the structure of the cursor. I've googled, and not found any way to do it.
    So, before I give up on it and go for a different solution, I just thought I'd check here to see if anyone else has attempted this? Or am I right in now thinking it's just not do-able.
    thanks in advance.

    Not a good idea to bulk collect in PL/SQL on the behalf of an external client like Forms.
    A bulk collect does a single thing only - it reduces the context switching between the PL/SQL and SQL engines. If you fetch a 1000 rows one at a time, then that fetch statement will cause a 1000 context switches as PL/SQL needs to step into the SQL engine in order to copy that row's data into PL/SQL.
    If you do a bulk fetch of a 100 rows/fetch, then you reduce the number of context switches to 10. A significant reduction.
    Okay, so now you hook Forms (or Java/Delphi/C#/etc) into this chain and push that bulk collection from a PL/SQL variable to this client. What do you achieve? Not much as you're now offsetting that reduction in context switches with more memory that needs to be used (that PL/SQL collection buffer needs PGA memory), and you add the overheads of first pulling the data from the db buffer cache into PL/SQL and then to the client.
    PL/SQL makes a very poor data cache for a client - the db buffer cache was designed exactly for that purpose. And is far superior than anything we can code in PL/SQL for the same role.
    It is much simpler, more robust, to rather fetch the data directly from the db buffer cache - no intermediate PL/SQL caching and buffering when fetching data. This will also scale better and perform better.
    The ideal is to use PL/SQL to implement a business logic layer, security, pre-processing, validation and other good stuff for the client - and then return a ref cursor to the client. Allowing the client to use that prepared cursor to fetch data directly from the db buffer cache.

  • Bulk collection PL/SQL table

    Hi all,
    10g version 10.2.0.1
    What approach can I take to accomplish the following.
    I need to build a collection based on the result set of two SQL statements within a loop.
    Example:
    FUNCTION( get_info )IS
    RETURN retrieval_pkg_public_ty
    PIPELINED
    TYPE ret_tab IS TABLE OF ret_rec;
    FOR i IN 1 .. 2
    LOOP
    SELECT...
    BULK COLLECT into ret_tbl
    FROM(SELECT...
    FROM(SELECT..
    quite a large SQL statement...
    WHERE
    x = parameter_value, --parameter changes on based on i values
    y = parameter_value, --parameter changes on based on i values
    END LOOP;
    FOR i IN ret_tbl.FIRST..ret_tbl.LAST
    LOOP
    PIPE ROW...
    END LOOP;
    I can use a global temporary table to hold the results of each loop and them select from gtt, however I would prefer to use a table function.
    thanks
    Mark

    user1602736 wrote:
    Currently, I have a procedure that is called within a package that returns a SYS_REFCURSOR.
    Current code in procedure is
    FOR i IN 1..2
    LOOP
    INSERt INTO gtt
    END LOOP;Why not simply populate the GTT using an INSERT INTO gtt SELECT ... FROM source WHERE .. ?
    I wanted to avoid creating a gtt to accomplish above.Why? What problems with this GTT approach do you think there are?
    The cursor only returns around 50 records. The record has around 20 data fieldsRemember that if you store this as a PL/SQL collection (there's no such thing as PL "+table+"), this collection resides in expensive private process memory (the PGA). If there a 100 sessions using this code, then there will be a 100 copies of this collection.
    On the other hand, a GTT does not reside in expensive private memory. And it can scale to a 1000 rows in future, without affecting performance (remember that GTTs can be indexed - collections not). For a collection, you will pay an excessive price in memory for keeping that 1000 rows in the PGA.
    GTTs are not a bad thing. Collections are not a bad thing. They are tools for addressing specific problems. Your task is to select the right tool for the job. Caching SQL row data in a PL/SQL collection is almost never the right tool for the job, as it requires private process memory and uses a very simplistic data structure (does not support indexes and so on).

  • Need to increase performance-bulk collect in cursor with limit and in the for loop inserting into the trigger table

    Hi all,
    I have a performance issue in the below code,where i am trying to insert the data from table_stg into target_tab and in parent_tab tables and then to child tables via cursor with bulk collect .the target_tab and parent_tab are huge tables and have a row wise trigger enabled on it .the trigger is mandatory . This timetaken for this block to execute is 5000 seconds.Now my requirement is to reduce it to 5 to 10 mins.
    can someone please guide me here.Its bit urgent .Awaiting for your response.
    declare
    vmax_Value NUMBER(5);
      vcnt number(10);
      id_val number(20);
      pc_id number(15);
      vtable_nm VARCHAR2(100);
      vstep_no  VARCHAR2(10);
      vsql_code VARCHAR2(10);
      vsql_errm varchar2(200);
      vtarget_starttime timestamp;
      limit_in number :=10000;
      idx           number(10);
              cursor stg_cursor is
             select
                   DESCRIPTION,
                   SORT_CODE,
                   ACCOUNT_NUMBER,
                     to_number(to_char(CORRESPONDENCE_DATE,'DD')) crr_day,
                     to_char(CORRESPONDENCE_DATE,'MONTH') crr_month,
                     to_number(substr(to_char(CORRESPONDENCE_DATE,'DD-MON-YYYY'),8,4)) crr_year,
                   PARTY_ID,
                   GUID,
                   PAPERLESS_REF_IND,
                   PRODUCT_TYPE,
                   PRODUCT_BRAND,
                   PRODUCT_HELD_ID,
                   NOTIFICATION_PREF,
                   UNREAD_CORRES_PERIOD,
                   EMAIL_ID,
                   MOBILE_NUMBER,
                   TITLE,
                   SURNAME,
                   POSTCODE,
                   EVENT_TYPE,
                   PRIORITY_IND,
                   SUBJECT,
                   EXT_PRD_ID_TX,
                   EXT_PRD_HLD_ID_TX,
                   EXT_SYS_ID,
                   EXT_PTY_ID_TX,
                   ACCOUNT_TYPE_CD,
                   COM_PFR_TYP_TX,
                   COM_PFR_OPT_TX,
                   COM_PFR_RSN_CD
             from  table_stg;
    type rec_type is table of stg_rec_type index by pls_integer;
    v_rt_all_cols rec_type;
    BEGIN
      vstep_no   := '0';
      vmax_value := 0;
      vtarget_starttime := systimestamp;
      id_val    := 0;
      pc_id     := 0;
      success_flag := 0;
              vstep_no  := '1';
              vtable_nm := 'before cursor';
        OPEN stg_cursor;
              vstep_no  := '2';
              vtable_nm := 'After cursor';
       LOOP
              vstep_no  := '3';
              vtable_nm := 'before fetch';
    --loop
        FETCH stg_cursor BULK COLLECT INTO v_rt_all_cols LIMIT limit_in;
                  vstep_no  := '4';
                  vtable_nm := 'after fetch';
    --EXIT WHEN v_rt_all_cols.COUNT = 0;
        EXIT WHEN stg_cursor%NOTFOUND;
    FOR i IN 1 .. v_rt_all_cols.COUNT
      LOOP
       dbms_output.put_line(upper(v_rt_all_cols(i).event_type));
        if (upper(v_rt_all_cols(i).event_type) = upper('System_enforced')) then
                  vstep_no  := '4.1';
                  vtable_nm := 'before seq sel';
              select PC_SEQ.nextval into pc_id from dual;
                  vstep_no  := '4.2';
                  vtable_nm := 'before insert corres';
              INSERT INTO target1_tab
                           (ID,
                            PARTY_ID,
                            PRODUCT_BRAND,
                            SORT_CODE,
                            ACCOUNT_NUMBER,
                            EXT_PRD_ID_TX,         
                            EXT_PRD_HLD_ID_TX,
                            EXT_SYS_ID,
                            EXT_PTY_ID_TX,
                            ACCOUNT_TYPE_CD,
                            COM_PFR_TYP_TX,
                            COM_PFR_OPT_TX,
                            COM_PFR_RSN_CD,
                            status)
             VALUES
                            (pc_id,
                             v_rt_all_cols(i).party_id,
                             decode(v_rt_all_cols(i).product_brand,'LTB',2,'HLX',1,'HAL',1,'BOS',3,'VER',4,0),
                             v_rt_all_cols(i).sort_code,
                             'XXXX'||substr(trim(v_rt_all_cols(i).ACCOUNT_NUMBER),length(trim(v_rt_all_cols(i).ACCOUNT_NUMBER))-3,4),
                             v_rt_all_cols(i).EXT_PRD_ID_TX,
                             v_rt_all_cols(i).EXT_PRD_HLD_ID_TX,
                             v_rt_all_cols(i).EXT_SYS_ID,
                             v_rt_all_cols(i).EXT_PTY_ID_TX,
                             v_rt_all_cols(i).ACCOUNT_TYPE_CD,
                             v_rt_all_cols(i).COM_PFR_TYP_TX,
                             v_rt_all_cols(i).COM_PFR_OPT_TX,
                             v_rt_all_cols(i).COM_PFR_RSN_CD,
                             NULL);
                  vstep_no  := '4.3';
                  vtable_nm := 'after insert corres';
        else
              select COM_SEQ.nextval into id_val from dual;
                  vstep_no  := '6';
                  vtable_nm := 'before insertcomm';
          if (upper(v_rt_all_cols(i).event_type) = upper('REMINDER')) then
                vstep_no  := '6.01';
                  vtable_nm := 'after if insertcomm';
              insert into parent_tab
                 (ID ,
                 CTEM_CODE,
                 CHA_CODE,            
                 CT_CODE,                           
                 CONTACT_POINT_ID,             
                 SOURCE,
                 RECEIVED_DATE,                             
                 SEND_DATE,
                 RETRY_COUNT)
              values
                 (id_val,
                  lower(v_rt_all_cols(i).event_type), 
                  decode(v_rt_all_cols(i).product_brand,'LTB',2,'HLX',1,'HAL',1,'BOS',3,'VER',4,0),
                  'Email',
                  v_rt_all_cols(i).email_id,
                  'IADAREMINDER',
                  systimestamp,
                  systimestamp,
                  0);  
         else
                vstep_no  := '6.02';
                  vtable_nm := 'after else insertcomm';
              insert into parent_tab
                 (ID ,
                 CTEM_CODE,
                 CHA_CODE,            
                 CT_CODE,                           
                 CONTACT_POINT_ID,             
                 SOURCE,
                 RECEIVED_DATE,                             
                 SEND_DATE,
                 RETRY_COUNT)
              values
                 (id_val,
                  lower(v_rt_all_cols(i).event_type), 
                  decode(v_rt_all_cols(i).product_brand,'LTB',2,'HLX',1,'HAL',1,'BOS',3,'VER',4,0),
                  'Email',
                  v_rt_all_cols(i).email_id,
                  'CORRESPONDENCE',
                  systimestamp,
                  systimestamp,
                  0); 
            END if; 
                  vstep_no  := '6.11';
                  vtable_nm := 'before chop';
             if (v_rt_all_cols(i).ACCOUNT_NUMBER is not null) then 
                      v_rt_all_cols(i).ACCOUNT_NUMBER := 'XXXX'||substr(trim(v_rt_all_cols(i).ACCOUNT_NUMBER),length(trim(v_rt_all_cols(i).ACCOUNT_NUMBER))-3,4);
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)
              values
                (id_val,
                 'IB.Correspondence.AccountNumberMasked',
                 v_rt_all_cols(i).ACCOUNT_NUMBER);
             end if;
                  vstep_no  := '6.1';
                  vtable_nm := 'before stateday';
             if (v_rt_all_cols(i).crr_day is not null) then 
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)
              values
                (id_val,
                 --'IB.Correspondence.Date.Day',
                 'IB.Crsp.Date.Day',
                 v_rt_all_cols(i).crr_day);
             end if;
                  vstep_no  := '6.2';
                  vtable_nm := 'before statemth';
             if (v_rt_all_cols(i).crr_month is not null) then 
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)
              values
                (id_val,
                 --'IB.Correspondence.Date.Month',
                 'IB.Crsp.Date.Month',
                 v_rt_all_cols(i).crr_month);
             end if;
                  vstep_no  := '6.3';
                  vtable_nm := 'before stateyear';
             if (v_rt_all_cols(i).crr_year is not null) then 
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)
              values
                (id_val,
                 --'IB.Correspondence.Date.Year',
                 'IB.Crsp.Date.Year',
                 v_rt_all_cols(i).crr_year);
             end if;
                  vstep_no  := '7';
                  vtable_nm := 'before type';
               if (v_rt_all_cols(i).product_type is not null) then
                  insert into child_tab
                     (COM_ID,                                            
                     KEY,                                                                                                                                        
                     VALUE)
                  values
                    (id_val,
                     'IB.Product.ProductName',
                   v_rt_all_cols(i).product_type);
                end if;
                  vstep_no  := '9';
                  vtable_nm := 'before title';         
              if (trim(v_rt_all_cols(i).title) is not null) then
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE )
              values
                (id_val,
                 'IB.Customer.Title',
                 trim(v_rt_all_cols(i).title));
              end if;
                  vstep_no  := '10';
                  vtable_nm := 'before surname';
              if (v_rt_all_cols(i).surname is not null) then
                insert into child_tab
                   (COM_ID,                                            
                   KEY,                                                                                                                                          
                   VALUE)
                values
                  (id_val,
                  'IB.Customer.LastName',
                  v_rt_all_cols(i).surname);
              end if;
                            vstep_no  := '12';
                            vtable_nm := 'before postcd';
              if (trim(v_rt_all_cols(i).POSTCODE) is not null) then
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)                              
               values
                (id_val,
                 'IB.Customer.Addr.PostCodeMasked',
                  substr(replace(v_rt_all_cols(i).POSTCODE,' ',''),length(replace(v_rt_all_cols(i).POSTCODE,' ',''))-2,3));
              end if;
                            vstep_no  := '13';
                            vtable_nm := 'before subject';
              if (trim(v_rt_all_cols(i).SUBJECT) is not null) then
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)                              
               values
                (id_val,
                 'IB.Correspondence.Subject',
                  v_rt_all_cols(i).subject);
              end if;
                            vstep_no  := '14';
                            vtable_nm := 'before inactivity';
              if (trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) is null or
                  trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) = '3' or
                  trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) = '6' or
                  trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) = '9') then
              insert into child_tab
                 (COM_ID,                                            
                 KEY,                                                                                                                                            
                 VALUE)                              
               values
                (id_val,
                 'IB.Correspondence.Inactivity',
                  v_rt_all_cols(i).UNREAD_CORRES_PERIOD);
              end if;
                          vstep_no  := '14.1';
                          vtable_nm := 'after notfound';
        end if;
                          vstep_no  := '15';
                          vtable_nm := 'after notfound';
        END LOOP;
        end loop;
                          vstep_no  := '16';
                          vtable_nm := 'before closecur';
        CLOSE stg_cursor;
                          vstep_no  := '17';
                          vtable_nm := 'before commit';
        DELETE FROM table_stg;
      COMMIT;
                          vstep_no  := '18';
                          vtable_nm := 'after commit';
    EXCEPTION
    WHEN OTHERS THEN
      ROLLBACK;
      success_flag := 1;
      vsql_code := SQLCODE;
      vsql_errm := SUBSTR(sqlerrm,1,200);
      error_logging_pkg.inserterrorlog('samp',vsql_code,vsql_errm, vtable_nm,vstep_no);
      RAISE_APPLICATION_ERROR (-20011, 'samp '||vstep_no||' SQLERRM:'||SQLERRM);
    end;
    Thanks

    Its bit urgent
    NO - it is NOT urgent. Not to us.
    If you have an urgent problem you need to hire a consultant.
    I have a performance issue in the below code,
    Maybe you do and maybe you don't. How are we to really know? You haven't posted ANYTHING indicating that a performance issue exists. Please read the FAQ for how to post a tuning request and the info you need to provide. First and foremost you have to post SOMETHING that actually shows that a performance issue exists. Troubleshooting requires FACTS not just a subjective opinion.
    where i am trying to insert the data from table_stg into target_tab and in parent_tab tables and then to child tables via cursor with bulk collect .the target_tab and parent_tab are huge tables and have a row wise trigger enabled on it .the trigger is mandatory . This timetaken for this block to execute is 5000 seconds.Now my requirement is to reduce it to 5 to 10 mins.
    Personally I think 5000 seconds (about 1 hr 20 minutes) is very fast for processing 800 trillion rows of data into parent and child tables. Why do you think that is slow?
    Your code has several major flaws that need to be corrected before you can even determine what, if anything, needs to be tuned.
    This code has the EXIT statement at the beginning of the loop instead of at the end
        FETCH stg_cursor BULK COLLECT INTO v_rt_all_cols LIMIT limit_in;
                  vstep_no  := '4';
                  vtable_nm := 'after fetch';
    --EXIT WHEN v_rt_all_cols.COUNT = 0;
        EXIT WHEN stg_cursor%NOTFOUND;
    The correct place for the %NOTFOUND test when using BULK COLLECT is at the END of the loop; that is, the last statement in the loop.
    You can use a COUNT test at the start of the loop but ironically you have commented it out and have now done it wrong. Either move the NOTFOUND test to the end of the loop or remove it and uncomment the COUNT test.
    WHEN OTHERS THEN
      ROLLBACK;
    That basically says you don't even care what problem occurs or whether the problem is for a single record of your 10,000 in the collection. You pretty much just throw away any stack trace and substitute your own message.
    Your code also has NO exception handling for any of the individual steps or blocks of code.
    The code you posted also begs the question of why you are using NAME=VALUE pairs for child data rows? Why aren't you using a standard relational table for this data?
    As others have noted you are using slow-by-slow (row by row processing). Let's assume that PL/SQL, the bulk collect and row-by-row is actually necessary.
    Then you should be constructing the parent and child records into collections and then inserting them in BULK using FORALL.
    1. Create a collection for the new parent rows
    2. Create a collection for the new child rows
    3. For each set of LIMIT source row data
      a. empty the parent and child collections
      b. populate those collections with new parent/child data
      c. bulk insert the parent collection into the parent table
      d. bulk insert the child collection into the child table
    And unless you really want to either load EVERYTHING or abandon everything you should use bulk exception handling so that the clean data gets processed and only the dirty data gets rejected.

  • How to improve performance using bulk collects with plsql tables or arrays

    Hi All,
    my procedure is like this
    declare
    cursor c1 is select ----------------------
    begin
    assigning to variables
    validations on that variables
    --50 validations are here --
    insert into a table
    end;
    we have created indexes on primary keys,
    i want to use
    DECLARE
    CURSOR a_cur IS
    SELECT program_id
    FROM airplanes;
    TYPE myarray IS TABLE OF a_cur%ROWTYPE;
    cur_array myarray;
    BEGIN
    OPEN a_cur;
    LOOP
    FETCH a_cur BULK COLLECT INTO cur_array LIMIT 100;
    ***---------can i assign cursor data to the plsql table variables or array***
    ***validate on the pl sql variable as---***
    i
    nsert into a table
    EXIT WHEN a_cur%NOTFOUND;
    END LOOP;
    CLOSE a_cur;
    END;
    Edited by: Veekay on Oct 21, 2011 4:28 AM

    Fastest way often is this:
    insert /*+append */
    into aTable
    select * from airplanes;
    commit;The select and insert part can even be done in parallel if needed.
    However if the oparation is complex or the dataset is very very very very very large or the programmer is decent but not excellent then the bulk approach should be considered. It is often a pretty stable and linear scaling approach.
    The solution depends a little on the database version.
    LOOP
      FETCH a_cur BULK COLLECT INTO cur_array LIMIT 100;
      EXIT WHEN a_cur.count = 0;
      forall i in a_cur.first.. a_cur.last
      insert into aTable (id)
      values (a_cur(i));
    END LOOP;
    ...If you have more then one column then you might need a single collection for each column. Other possibilities depend on the db version.
    Also: do not exit using a_cur%NOTFOUND. This is wrong! You might loose records from the end of the data set.

Maybe you are looking for

  • Calling a super.ssuper.method but your super is a abstract class.

    Dear guys, Is that possible to invoke your super's super's method but your super is a abstract class? like: class GO {   public void draw() { } } abstract class GORunner extends GO {} class GOCounter extends GORunner { public void draw() { super.supe

  • External hard drive between mac and pc

    i got a "my passport" external hard drive to load all my stuff onto it from my mac, to be used on our pc. i have to reformat the hard drive for a mac before i can even copy my items on it. but my stupid question is, will it all open up fine on the pc

  • How to Save a file in InDesign 5 so it will open in InDesign 3 (no InDesign 4)

    How do I save an InDesign 5 file in InDesign 5 so it can be opened by my graphic designer in In Design 3. Neither of us have CS4. She thinks she cannot open an .IDML file on In Design 3.  Can she? What do I do to save it to get it to her so she can o

  • Quicken data file names are mysteriously being change on my iDisk

    within the last couple of days my Quicken data file names are mysteriously being change on my iDisk which seem to make them inaccesable.  Not sure why this is happening

  • IOS "Mail" font size keeps varying...

    How do I get Mail on the iPhone/iPad to always display the same font size? Sometimes the font is too small to be readable and I have to pinch outwards to increase it. It gets annoying after several instances... Thanks! Fernando