BulkCollect FORALL

How to use forall here
SQL> DECLARE
  2     CURSOR driver IS SELECT * FROM SCOTT.EMP;
  3     TYPE recs_type IS TABLE OF SCOTT.EMP%ROWTYPE INDEX BY BINARY_INTEGER;
  4     recs recs_type;
  5  BEGIN
  6     OPEN driver;
  7     FETCH driver BULK COLLECT INTO recs;
  8     CLOSE driver;
  9     FORALL i IN 1..recs.COUNT
10             UPDATE MY_EMP SET ENAME = UPPER(recs(i).ENAME)
11             WHERE EMPNO = recs(I).EMPNO;
12  END;
13  /
                UPDATE MY_EMP SET ENAME = UPPER(recs(i).ENAME)
ERROR at line 10:
ORA-06550: line 10, column 35:
PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND
table of records
ORA-06550: line 10, column 35:
PLS-00382: expression is of wrong type
ORA-06550: line 11, column 17:
PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND
table of records
ORA-06550: line 11, column 17:
PLS-00382: expression is of wrong type
ORA-06550: line 10, column 35:
PL/SQL: ORA-22806: not an object or REF
ORA-06550: line 10, column 3:
PL/SQL: SQL Statement ignored

The statement boils down to
update emp set ename=upper(ename);
And that is the most efficient implementation there is, BULK colllect will be several magnitudes slower.
No solution is required, or this must be an exercise in the course 'How to build an unscalable application'
Sybrand Bakker
Senior Oracle DBA

Similar Messages

  • BulkCollect ...ForAll ... Limit question

    Hi,
    I'm using the BulkCollect and ForAll method. What is the appropriate quantity to use in the "LIMIT" parameter in the BulkCollect statement. My cursor has 350 000 records. What would be the best number to put there?
    FETCH CurStatsVtesReg BULK COLLECT
    INTO vNoCentreDistribution
    ,vCliIdClient
    ,vNoClient
    ,vPrdIdProduit
    ,vNoProduit
    ,vCodeRegionTerritoriale
    ,vQteVteReg
    LIMIT 50000;
    Thanks

    Exactly. Only you are familiar with the environment your software is going to run in.
    On a data warehouse, I'm using a LIMIT of 10000 for a bulk process that sync's with production - as that is the optimal setting ito performance and PGA utilisation.
    On another high volume platform, I'm using a LIMIT of 100.
    Horse for courses. And do not let anyone else tell you otherwise. There are no fixed magic and golden parameters in performance tuning.
    Best that can be given to you is performance guidelines. However, at the end of the day no two production environments are identical in every respect. So what works in one may not work in another - and often not.
    A word of advice though. Do not hardcode the LIMIT clause in your code. Consider using package constants instead.
    Reason. This allows the DBA or Production Admin/Owner to further fine-tune your code. During initial deployment your process may have been run with others during peak periods and the LIMIT clause reduced to a 100 or even less.
    Now the same code is scheduled for off-peak periods where it will have most of the free system memory of that platform for itself. Having a bunch of constants to change allows the LIMIT to be changed.
    In other words, when you code for performance, provide performance knobs for the guys in production to turn up and down. Instead of hardcoding performance related parameters in your code.

  • Using forall and bulkcollect together

    Hey group,
    I am trying to use bulk collect and forall together.
    i have bulk collect on 3 columns and insert is on more than 3 columns.can anybody tell me how to reference those collection objects in bulk collect statement.
    you can see the procedure,i highlighted things am trying.
    Please let me know,if am clear enough.
    PROCEDURE do_insert
    IS
    PROCEDURE process_insert_record
    IS
    CURSOR c_es_div_split
    IS
    SELECT div_id
    FROM zrep_mpg_div
    WHERE div_id IN ('PC', 'BP', 'BI', 'CI', 'CR');
    PROCEDURE write_record
    IS
    CURSOR c_plan_fields
    IS
    SELECT x.comp_plan_id, x.comp_plan_cd, cp.comp_plan_nm
    FROM cp_div_xref@dm x, comp_plan@dm cp
    WHERE x.comp_plan_id = cp.comp_plan_id
    AND x.div = v_div
    AND x.sorg_cd = v_sorg_cd
    AND x.comp_plan_yr = TO_NUMBER (TO_CHAR (v_to_dt, 'yyyy'));
    TYPE test1 IS TABLE OF c_plan_fields%ROWTYPE
    INDEX BY BINARY_INTEGER;
    test2 test1;
    BEGIN -- write_record
    OPEN c_plan_fields;
    FETCH c_plan_fields bulk collect INTO test2;
    CLOSE c_plan_fields;
    ForAll X In 1..test2.last
    INSERT INTO cust_hier
    (sorg_cd, cust_cd, bunt, --DP
    div,
    from_dt,
    to_dt,
    cust_ter_cd, cust_rgn_cd, cust_grp_cd,
    cust_area_cd, sorg_desc, cust_nm, cust_ter_desc,
    cust_rgn_desc, cust_grp_desc, cust_area_desc,
    cust_mkt_cd, cust_mkt_desc, curr_flag,
    last_mth_flag, comp_plan_id, comp_plan_cd,
    comp_plan_nm, asgn_typ, lddt
    VALUES (v_sorg_cd, v_cust_cd, v_bunt, --DP
    v_div,
    TRUNC (v_from_dt),
    TO_DATE (TO_CHAR (v_to_dt, 'mmddyyyy') || '235959',
    'mmddyyyyhh24miss'
    v_ter, v_rgn, v_grp,
    v_area, v_sorg_desc, v_cust_nm, v_cust_ter_desc,
    v_rgn_desc, v_grp_desc, v_area_desc,
    v_mkt, v_mkt_desc, v_curr_flag,
    v_last_mth_flag, test2(x).comp_plan_id,test2(x).comp_plan_cd,
    test2(x).comp_plan_nm, v_asgn_typ, v_begin_dt
    v_plan_id := 0;
    v_plan_cd := 0;
    v_plan_nm := NULL;
    v_out_cnt := v_out_cnt + 1;
    IF doing_both
    THEN
    COMMIT;
    ELSE
    -- commiting v_commit_rows rows at a time.
    IF v_out_cnt >= v_commit_cnt
    THEN
    COMMIT;
    p.l ( 'Commit point reached: '
    || v_out_cnt
    || 'at: '
    || TO_CHAR (SYSDATE, 'mm/dd hh24:mi:ss')
    v_commit_cnt := v_commit_cnt + v_commit_rows;
    END IF;
    END IF;
    END write_record;

    Ugly code.
    Bulk processing does what in PL? One and one thing only. It reduces context switching between the PL and SQL engines. That is it. Nothing more. It is not magic that increases performance. And there is a penalty to pay for the reduction in context switching - memory. Very expensive PGA memory.
    To reduce the context switches, bigger chunks of data are passed between the PL and SQL engines. You have coded a single fetch for all the rows from the cursor. All that data collected from the SQL engine has to be stored in the PL engine. This requires memory. The more rows, the more memory. And the memory used is dedicated non-shared server memory. The worse kind to use on a server where resources need to be shared in order for the server to scale.
    Use the LIMIT clause. That controls how many rows are fetched. And thus you manage just how much memory is consumed.
    And why the incremental commit? What do you think you are achieving with that? Except consuming more resources by doing more commits.. not to mention risking data integrity as this process can now fail and result in only partial changes. And only changing some of the rows when you need to change all the rows is corrupting the data in the database in my book.
    Also, why use PL at all? Surely you can do a INSERT into <table1> SELECT .. FROM <table2>,<table3> WHERE ...
    And with this, you can also use parallel processing (DML). You can use direct path inserts. You do not need a single byte of PL engine code or memory. You do not have to ship data between the PL and SQL engines. What you now have is fast performing code that can scale.

  • 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

  • Not enough values for FORALL

    Hi,
    I have written this procedure and I am getting
    LINE/COL ERROR
    69/5 PL/SQL: SQL Statement ignored
    83/11 PL/SQL: ORA-00947: not enough values
    CREATE OR REPLACE PROCEDURE f_t_s (P_F IN VARCHAR2)
    IS
    TYPE quote_cols_rt IS RECORD
    twitter_gid twitter.twitter_gid%TYPE,
    twitter_xid twitter.twitter_xid%TYPE,
    origin_location_type twitter.origin_location_type%TYPE,
    destination_location_type twitter.destination_location_type%TYPE,
    is_hazardous twitter.is_hazardous%TYPE,
    perspective twitter.perspective%TYPE,
    twitter_option twitter.twitter_option%TYPE,
    servprov_gid twitter.servprov_gid%TYPE,
    origin_search_value twitter.origin_search_value%TYPE,
    destination_search_value twitter.destination_search_value%TYPE,
    domain_name twitter.domain_name%TYPE,
    is_customer_rates_only twitter.is_customer_rates_only%TYPE
    TYPE twitter_cols_tt IS TABLE OF twitter_cols_rt INDEX BY PLS_INTEGER;
    twitter_cols_t twitter_cols_tt;
    BEGIN
    SELECT all_spec twitter_gid,
    SUBSTR(all_spec,7) twitter_xid,
    'location_code' origin_location_type,
    'location_code' destination_location_type,
    'N' is_hazardous,
    'B' perspective,
    'O' twitter_option,
    'INDIA.'||servprov_xid servprov_gid,
    SUBSTR(tm,1,2) ||':'||SUBSTR(tm,3) origin_search_value,
    Location_xid destination_search_value,
    'INDIA' domain_name,
    'N' is_customer_rates_only
    BULK COLLECT INTO twitter_cols_t
    FROM
    (SELECT x.*,
    Q.twitter_gid
    FROM
    (SELECT 'INDIA.FS_'||H.servprov_xid||'_'||D.Location_xid||'_'||T.tm all_spec,
    servprov_xid ,
    tm ,
    Location_xid
    FROM
    (SELECT Location_xid
    FROM location
    WHERE location_xid IN ('1')
    AND domain_name ='INDIA'
    ) D,
    (SELECT servprov_xid
    FROM servprov
    WHERE(servprov_gid LIKE 'P_F%'
    AND SUBSTR(servprov_xid,2,1) IN ('2'))
    OR servprov_gid ='INDIA.FRESHMISC'
    ) H,
    (SELECT lpad(rownum-1,2,'0') ||'00' tm FROM sea WHERE rownum<25
    UNION
    SELECT lpad(rownum-1,2,'0') ||'30' tm FROM sea WHERE rownum<25
    ) T
    ) x,
    (SELECT * FROM twitter WHERE twitter_gid LIKE 'INDIA.FS%'
    ) Q
    WHERE x.all_spec=Q.twitter_gid(+)
    WHERE twitter_gid IS NULL;
    FORALL i in 1 .. twitter_cols_t.count
    --LOOP
    INSERT
    INTO twitter
    (twitter_gid ,
    twitter_xid ,
    origin_location_type ,
    destination_location_type,
    is_hazardous ,
    perspective ,
    twitter_option ,
    servprov_gid ,
    origin_search_value ,
    destination_search_value ,
    domain_name ,
    is_customer_rates_only)
    VALUES
    twitter_cols_t (i);
    --END LOOP;
    END f_t_s;
    Any idea where I am doing mistake
    Thanks in Advance,
    DIDI

    Hi,
    That was my typing mistake....
    This is correct code
    CREATE OR REPLACE PROCEDURE f_t_s (P_F IN VARCHAR2)
    IS
    TYPE twitter_cols_rt IS RECORD
    twitter_gid twitter.twitter_gid%TYPE,
    twitter_xid twitter.twitter_xid%TYPE,
    origin_location_type twitter.origin_location_type%TYPE,
    destination_location_type twitter.destination_location_type%TYPE,
    is_hazardous twitter.is_hazardous%TYPE,
    perspective twitter.perspective%TYPE,
    twitter_option twitter.twitter_option%TYPE,
    servprov_gid twitter.servprov_gid%TYPE,
    origin_search_value twitter.origin_search_value%TYPE,
    destination_search_value twitter.destination_search_value%TYPE,
    domain_name twitter.domain_name%TYPE,
    is_customer_rates_only twitter.is_customer_rates_only%TYPE
    TYPE twitter_cols_tt IS TABLE OF twitter_cols_rt INDEX BY PLS_INTEGER;
    twitter_cols_t twitter_cols_tt;
    BEGIN
    SELECT all_spec twitter_gid,
    SUBSTR(all_spec,7) twitter_xid,
    'location_code' origin_location_type,
    'location_code' destination_location_type,
    'N' is_hazardous,
    'B' perspective,
    'O' twitter_option,
    'INDIA.'||servprov_xid servprov_gid,
    SUBSTR(tm,1,2) ||':'||SUBSTR(tm,3) origin_search_value,
    Location_xid destination_search_value,
    'INDIA' domain_name,
    'N' is_customer_rates_only
    BULK COLLECT INTO twitter_cols_t
    FROM
    (SELECT x.*,
    Q.twitter_gid
    FROM
    (SELECT 'INDIA.FS_'||H.servprov_xid||'_'||D.Location_xid||'_'||T.tm all_spec,
    servprov_xid ,
    tm ,
    Location_xid
    FROM
    (SELECT Location_xid
    FROM location
    WHERE location_xid IN ('1')
    AND domain_name ='INDIA'
    ) D,
    (SELECT servprov_xid
    FROM servprov
    WHERE(servprov_gid LIKE 'P_F%'
    AND SUBSTR(servprov_xid,2,1) IN ('2'))
    OR servprov_gid ='INDIA.FRESHMISC'
    ) H,
    (SELECT lpad(rownum-1,2,'0') ||'00' tm FROM sea WHERE rownum<25
    UNION
    SELECT lpad(rownum-1,2,'0') ||'30' tm FROM sea WHERE rownum<25
    ) T
    ) x,
    (SELECT * FROM twitter WHERE twitter_gid LIKE 'INDIA.FS%'
    ) Q
    WHERE x.all_spec=Q.twitter_gid(+)
    WHERE twitter_gid IS NULL;
    FORALL i in 1 .. twitter_cols_t.count
    --LOOP
    INSERT
    INTO twitter
    (twitter_gid ,
    twitter_xid ,
    origin_location_type ,
    destination_location_type,
    is_hazardous ,
    perspective ,
    twitter_option ,
    servprov_gid ,
    origin_search_value ,
    destination_search_value ,
    domain_name ,
    is_customer_rates_only)
    VALUES
    twitter_cols_t (i);
    --END LOOP;
    END f_t_s;
    Thanks,
    DIDI

  • Deletion is taking long time using forall

    Hi,
           i am  inserting and deleting the rows using forall. insert taking less time to inset the rows but while coming to
    deletion it is taking more than 5 days long time to delete 18.5 million rows in a table using forall.
    the main table having 70 million rows.
    the code is..
       FETCH ref_typ  BULK COLLECT INTO l_id_tbl LIMIT 10000;
       begin
        FORALL i in  1..l_id_tbl.COUNT
           INSERT INTO   change_test (id,
                                 history,
                                 transaction,
                                 date)
                         VALUES (seq.nextval,
                                 'CHANGE_HIS',
                                 l_id_tbl(i),
                                 sysdate);
           exception
               when others then
                null;
        end;
        begin
            FoRALL i in 1..l_id_tbl.COUNT
              DELETE FROM change_his
                     where id = l_id_tbl(i);
           exception
               when others then
                 null;
       end;
      end loop;
    so  please give me a good solution  to delete the rows less than 5 days..

    Why are you wanting to do this using BULK COLLECT and FORALL?
    Why not just "insert ... select ..." and "delete ..."?
    Loading records into expensive PGA memory to insert them back on the database is bound to be slower (and use more server resources) than just doing a straight insert ... select ... statement.
    Explain exactly what you are trying to do.
    Re: 2. How do I ask a question on the forums?

  • Error While Executing FORALL

    Hello All,
    May i know why the following example from Oracle documentation is failing.
    CREATE TABLE coords (x NUMBER, y NUMBER);
    CREATE TYPE Pair AS OBJECT (m NUMBER, n NUMBER);
    DECLARE
       TYPE PairTab IS TABLE OF Pair;
       pairs PairTab := PairTab(Pair(1,2), Pair(3,4), Pair(5,6));
       TYPE NumTab IS TABLE OF NUMBER;
       nums NumTab := NumTab(1, 2, 3);
    BEGIN
       /* The following statement succeeds. */
       FORALL i in 1..3
          UPDATE coords SET (x, y) = (pairs(i).m, pairs(i).n)
             WHERE x = nums(i);
    END;
    Error:
    Error starting at line 37 in command:
    DECLARE
       TYPE PairTab IS TABLE OF Pair;
       pairs PairTab := PairTab(Pair(1,2), Pair(3,4), Pair(5,6));
       TYPE NumTab IS TABLE OF NUMBER;
       nums NumTab := NumTab(1, 2, 3);
    BEGIN
       /* The following statement succeeds. */
       FORALL i in 1..3
          UPDATE coords SET (x, y) = (pairs(i).m, pairs(i).n)
             WHERE x = nums(i);
    END;
    Error report:
    ORA-06550: line 9, column 34:
    PL/SQL: ORA-01767: UPDATE ... SET expression must be a subquery
    ORA-06550: line 9, column 7:
    PL/SQL: SQL Statement ignored
    06550. 00000 -  "line %s, column %s:\n%s"
    *Cause:    Usually a PL/SQL compilation error.
    *Action:
    Thank you.

    Based on your advise i did the below example,
    DECLARE
       TYPE PairTab IS TABLE OF Pair;
       pairs PairTab := PairTab(Pair(1,2), Pair(3,4), Pair(5,6),Pair(7,8),Pair(9,10));
       TYPE NumTab IS TABLE OF NUMBER;
       nums NumTab := NumTab(1,2,3,4,5);
       vnum1 NUMBER;
       vnum2 number;
    BEGIN
       FORALL i IN 1 .. 5
       UPDATE coords
       SET   (x, y) = (SELECT pairs(i).m, pairs(i).n
                       FROM dual)
       WHERE  x = nums(i);
    END;
    INSERT INTO coords VALUES(1,10);
    INSERT INTO coords VALUES(2,10);
    insert into coords values(3,10);
    INSERT INTO coords VALUES(4,10);
    INSERT INTO coords VALUES(5,10);
    commit;
    After insertng the data into coords table i execute the above plsql block i got the below output.I wonder how come rows 2,3 & 5 are updated with 9,10.
    Output:
    1
    2
    9
    10
    9
    10
    7
    8
    9
    10

  • Error While Using FORALL --

    Hi All,
    I am using FORALL for inserting 40000 records from the file to the table. After reading data from the file it has been stored in type Table array, But while executing FORALL statement its giving ora-00600. error.
    It is a memory error, some where I read to using LIMIT in fetch. But I am not using any fetch or Cursor. Can any body Help.
    SKM
    =================== ================= Package Code
    create or replace package insertpackage as
         TYPE tabSNO IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
         TYPE tabSNO1 IS TABLE OF VARCHAR2(1) INDEX BY BINARY_INTEGER;
         TYPE tabSDATE IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;
         TYPE SNO IS TABLE OF NUMBER(5) INDEX BY BINARY_INTEGER;
    procedure insertpro(snoArray IN SNO, sDate IN tabSDATE, sArray IN tabSNO, sArray1 IN tabSNO1);
    end insertpackage;
    create or replace package body insertpackage as
         procedure insertpro(snoArray IN SNO, sDate IN tabSDATE, sArray IN tabSNO, sArray1 IN tabSNO1) is
         begin
              forall i in 1..sArray.last
                   insert into test(s_no, s_date, s_co, s_type)
                   values(snoArray(i), TO_DATE(sDate(i),'YYYY-MM-DD HH24.MI.SS'), sArray(i), sArray1(i));
         end;
    end insertpackage;
    /

    Hi User,
    The error
    implementation restriction: cannot reference fields of BULK In-BIND table of recordsis because bulk bind cannot use table of composite types.
    Please See the below,
    http://dba-blog.blogspot.com/2005/08/using-of-bulk-collect-and-forall-for.html
    And rewrite your code like this,
    DECLARE
       CURSOR EMP_CUR
       IS
          SELECT EMPNO, ENAME
            FROM EMP;
       TYPE TAB_EMP_EMPNO IS TABLE OF EMP.EMPNO%TYPE;
       V_TAB_EMPNO   TAB_EMP_EMPNO;
       TYPE TAB_EMP_ENAME IS TABLE OF EMP.ENAME%TYPE;
       V_TAB_ENAME   TAB_EMP_ENAME;
    BEGIN
       OPEN EMP_CUR;
       FETCH EMP_CUR BULK COLLECT INTO V_TAB_EMPNO, V_TAB_ENAME;
       FORALL I IN V_TAB_EMPNO.FIRST .. V_TAB_EMPNO.LAST
          INSERT INTO EMP_TEMP
                      (EMPNO, ENAME
               VALUES (V_TAB_EMPNO (I), V_TAB_ENAME (I)
       CLOSE EMP_CUR;
    END;Thanks,
    Shankar

  • Using Sequence in FORALL Statement

    I'm using a package to get the nextval in a sequence object. Basically, it is a function that returns select user_seq.nextval from dual.
    But I get 'column not allowed here' error. PL/SQL: ORA-00984: column not allowed here
    OPEN users_ins ;
                 LOOP
                    FETCH         naf_users_ins
                    BULK COLLECT
                    INTO           arr_person_key
                                 , arr_person_id
                                 , arr_first_name
                                 , arr_middle_name
                                 , arr_last_name
                                 , arr_username
                                 , arr_user_status_seq
                                 , arr_creation_date
                                 , arr_comments
                   LIMIT         100 ;
    FORALL idx IN 1 ..  arr_person_key.COUNT
                     SAVE EXCEPTIONS
                       INSERT INTO users
                        (   user_seq
                          , person_key
                          , person_id
                          , first_name
                          , middle_name
                          , last_name
                          , username
                          , user_status_seq
                          , creation_date
                          , comments
                        VALUES  (   *pkg_admin.get_nextval*
                                  , arr_person_key(idx)
                                  , arr_person_id(idx)
                                  , arr_first_name(idx)
                                  , arr_middle_name(idx)
                                  , arr_last_name(idx)
                                  , arr_username(idx)
                                  , arr_user_status_seq(idx)
                                  , arr_creation_date(idx)
                                  , arr_comments(idx)
    EXIT WHEN users_ins%NOTFOUND ;
                 END LOOP ;
                 CLOSE users_ins;
    c/code]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

    Hi,
    I've recently completed a similar task, but I declared a collection with the rowtype of the table. I also added the sequence in the query of my cursor. Take a look at the following example.
    CREATE OR REPLACE PROCEDURE Insert_OR_ExternalService
    IS
    TYPE externalService_tbl IS TABLE OF OR_ExternalService%ROWTYPE;
    externalService externalService_tbl;
    CURSOR OR_ExternalServiceCursor
    IS
    select
    SEQ_ID.NEXTVAL as "Id",
    column as "ExternalId",
    column as "ExternalSystem",
    from table1
    where ...;
    BEGIN
    OPEN OR_ExternalServiceCursor;
    LOOP
    FETCH OR_ExternalServiceCursor BULK COLLECT INTO externalService LIMIT 1000;
    FORALL i IN 1 .. externalService.count
    INSERT INTO OR_ExternalService values externalService(i);
    COMMIT;
    EXIT WHEN OR_ExternalServiceCursor%NOTFOUND;
    END LOOP;
    CLOSE OR_ExternalServiceCursor;
    END;

  • PLS-00435: DML statement without BULK In-BIND cannot be used inside FORALL

    See code below: Have googled the error but not sure how to fix the code. ANy help would be most greatful.
    DECLARE
    CURSOR c1
    IS
    SELECT /*+ parallel(tr,8)*/ DISTINCT tr.ACC ACC, tr.MET_ID METID, to_char(max(TRUNC(PKG_LSR_IMPOSITION.convertXXMMDDToDate(tr.DATETR0))),'YYYY') dt
    FROM CTTR0FIL_CDC tr
    JOIN transaction_action_sd sd on (sd.TRANSACTION_CODE = tr.RESULT)
    WHERE sd.ACTION_TYPE = 'PAYMENT'
    and to_char(TRUNC(PKG_LSR_IMPOSITION.convertXXMMDDToDate(tr.DATETR0)),'YYYY') = '1987'
    GROUP BY tr.ACC, tr.MET_ID, to_char(TRUNC(PKG_LSR_IMPOSITION.convertXXMMDDToDate(tr.DATETR0)),'YYYY');
    SUBTYPE PAY_DATES IS c1%ROWTYPE;
    TYPE TMP_TABLE IS TABLE OF PAY_DATES INDEX BY PLS_INTEGER;
    TBROWS TMP_TABLE;
    temp VARCHAR2(100);
    Begin
    DBMS_OUTPUT.ENABLE(10000);
    OPEN c1;
    LOOP
    FETCH c1 BULK COLLECT INTO TBROWS LIMIT 1000;
    FORALL i IN 1..TBROWS.COUNT
    SELECT /*+ parallel(da,8)*/ da.ACC INTO temp
              FROM CTDA0FIL_CDC da
    WHERE da.ACC = TBROWS(i).ACC AND da.MET_ID = TBROWS(i).MET_ID AND da.ACC = '07000006P' AND da.MET_ID = 4;
         DBMS_OUTPUT.PUT_LINE('inside');
    EXIT WHEN c1%notfound;
    END LOOP;
    CLOSE c1;
    END;
    Thanks
    Simon

    I tried using a normal for loop instead of a forall loop (see code below). But this came up the error also see below. Or can I not use selects in this way???
    OPEN c1;
    LOOP
    FETCH c1 BULK COLLECT INTO tbrows LIMIT 1000;
    FOR i IN TBROWS.FIRST .. TBROWS.LAST
         LOOP
              SELECT /*+ parallel(da,8)*/ da.ACC INTO temp
              FROM CTDA0FIL_CDC da WHERE da.ACC = TBROWS(i).ACC AND da.MET_ID = TBROWS(i).MET_ID AND da.ACC = '07000006P' AND da.MET_ID = 4;
         DBMS_OUTPUT.PUT_LINE('inside');
    EXIT WHEN c1%notfound;
    END LOOP;
    END LOOP;
    CLOSE c1;
    END;
    Error:
    DECLARE
    ERROR at line 1:
    ORA-06502: PL/SQL: numeric or value error
    ORA-06512: at line 24

  • FORALL MERGE statement works in local database but not over database link

    Given "list", a collection of NUMBER's, the following FORALL ... MERGE statement should copy the appropriate data if the record specified by the list exists on both databases.
    forall i in 1..list.count
    merge into tbl@remote t
    using (select * from tbl
    where id = list(i)) s
    on (s.id = t.id)
    when matched then
    update set
    t.status = s.status
    when not matched then
    insert (id, status)
    values (s.id, s.status);
    But this does not work. No exceptions, but target table's record is unchanged and "sql%rowcount" is 0.
    If the target table is in the local database, the exact same statement works:
    forall i in 1..list.count
    merge into tbl2 t
    using (select * from tbl
    where id = list(i)) s
    on (s.id = t.id)
    when matched then
    update set
    t.status = s.status
    when not matched then
    insert (id, status)
    values (s.id, s.status);
    Does anyone have a clue why this may be a problem?
    Both databases are on Oracle 10g.
    Edited by: user652538 on 2009. 6. 12 오전 11:29
    Edited by: user652538 on 2009. 6. 12 오전 11:31
    Edited by: user652538 on 2009. 6. 12 오전 11:45

    Should throw an error in my opinion. The underlying reason for not working is basically because of
    SQL> merge into   t@remote t1
         using   (    select   sys.odcinumberlist (1) from dual) t2
            on   (1 = 1)
    when matched
    then
       update set i = 1
    Error at line 4
    ORA-22804: remote operations not permitted on object tables or user-defined type columnsSame reason as e.g.
    insert into t@remote select * from table(sys.odcinumberlist(1,2,3))doesn't work.

  • Issue in using Cursor+Dynamic SQL+ Bulk collect +FORALL

    Hi,
    I have a dynamic query which I need to use as a cursor to fetch records that inturn need to be inserted into a staging table.
    The issue I am facing is I am not sure how to declare the variable to fetch the records into. Since I am using a dynamic cursor how do I declare it?
    My code looks something like this -
    TYPE c_details_tbl_type IS REF CURSOR;
    c_details c_details_tbl_type;
    TYPE c_det_tbl_type IS TABLE OF c_details%ROWTYPE INDEX BY PLS_INTEGER;
    c_det_tbl c_det_tbl_type; -- ???
    BEGIN
    v_string1 := 'SELECT....'
    v_string2 := ' UNION ALL SELECT....'
    v_string3 := 'AND ....'
    v_string := v_string1||v_string2||v_string3;
    OPEN c_details FOR v_string;
    LOOP
    FETCH c_details BULK COLLECT
    INTO c_det_tbl LIMIT 1000;
    IF (c_det_tbl.COUNT > 0) THEN
              DELETE FROM STG;
              FORALL i IN 1..c_det_tbl.COUNT
              INSERT INTO STG
              VALUES (c_det_tbl(i));
    END IF;
    EXIT WHEN c_details%NOTFOUND;
    END LOOP;
    CLOSE c_details;
    END
    Thanks

    Why the bulk collect? All that this does is slow down the read process (SELECT) and write process (INSERT).
    Data selected needs (as a collection) to be pushed into the PGA memory of the PL/SQL engine. And then that very same data needs to be pushed again by the PL/SQL engine back to the database to be inserted. Why?
    It is a lot faster, needs a lot less resources, with fewer moving parts, to simply instruct the SQL engine to do both these steps using a single INSERT..SELECT statement. And this can support parallel DML too for scalability when data volumes get large.
    It is also pretty easy to make a single SQL statement like this dynamic and even support bind variables.
    Simplicity is the ultimate form of elegance. Pushing data needlessly around is not simple and thus not a very elegant way to address the problem.

  • Error in self increment varible value using "FORALL"

    CREATE OR REPLACE PROCEDURE BULK_COLLCT_PASS
    AS
    TYPE VAR_TYP IS VARRAY (32767) OF VARCHAR2 (32767);
    V_DSH_CM_NUMBER VAR_TYP;
    V_DSH_DATE VAR_TYP;
    V_DSH_TIME VAR_TYP;
    V_DSD_CM_NUMBER VAR_TYP;
    V_PLU_CODE VAR_TYP;
    V_DSD_DATE VAR_TYP;
    V_str_id VAR_TYP;
    LN_ITM NUMBER:=0;
    str_id number := 30001;
    CURSOR CUR_DBMG_SAL_HEAD
    IS
    SELECT DSH.CM_NUMBER,D_DSH_CM_DATE, D_DSH_CM_TIME
    FROM DBMG_SAL_HEAD DSH
    WHERE ROWNUM<6;
    BEGIN
    OPEN CUR_DBMG_SAL_HEAD;
    LOOP
    FETCH CUR_DBMG_SAL_HEAD BULK COLLECT
    INTO V_DSH_CM_NUMBER,
    V_DSH_DATE,
    V_DSH_TIME;
    FOR indx IN V_DSH_CM_NUMBER.FIRST .. V_DSH_CM_NUMBER.LAST
    LOOP
    SELECT CM_NUMBER, PLU_CODE,V_DSH_DATE(indx)
    BULK COLLECT
    INTO V_DSD_CM_NUMBER, V_PLU_CODE,V_DSD_DATE
    FROM DBMG_SAL_DETL DSD
    WHERE DSD.CM_NUMBER = V_DSH_CM_NUMBER(indx);
    --block1
    Ln_Itm := 0;
    FOR ind IN 1..V_DSD_CM_NUMBER.COUNT
    loop
    INSERT INTO PC_ALL_TAB
    VALUES(V_DSH_CM_NUMBER(indx),
    V_DSD_DATE(ind),
    V_DSD_CM_NUMBER(ind),
    V_PLU_CODE(ind),
    LN_ITM,
    str_id
    LN_ITM := LN_ITM +1;
    end loop;
    --block2                 
    END LOOP;
    EXIT WHEN CUR_DBMG_SAL_HEAD%NOTFOUND;
    END LOOP;
    commit;
    CLOSE CUR_DBMG_SAL_HEAD;
    DBMS_OUTPUT.PUT_LINE('COMPLETE..!');
    END ;
    Hi,
    I am using above code in which when code between "--block1 & --block2" is incrementing ln_itm value by 1 each time.
    so that after completion of code o/p is as below.
    SELECT DSH_CM_NUMBER, LN_ITM FROM PC_ALL_TAB;
    DSH_CM_NUMBER     LN_ITM
    1     4177424     0
    2     4177422     0
    3     4177426     0
    4     4177426     1
    5     4177426     2
    6     4177425     0
    7     4177427     0
    8     4177427     1
    9     4177427     2
    for each repeating value of cm_number its incresing by 1.
    but i wan to change "--block1 to --block2" in "FORALL". i did this but i m nt getting o/p is incresing value of ln_itm.
    kindly help me...
    code after changed to "FORALL"
    CREATE OR REPLACE PROCEDURE BULK_COLLCT_PASS
    AS
    TYPE VAR_TYP IS VARRAY (32767) OF VARCHAR2 (32767);
    V_DSH_CM_NUMBER VAR_TYP;
    V_DSH_DATE VAR_TYP;
    V_DSH_TIME VAR_TYP;
    V_DSD_CM_NUMBER VAR_TYP;
    V_PLU_CODE VAR_TYP;
    V_DSD_DATE VAR_TYP;
    V_str_id VAR_TYP;
    LN_ITM NUMBER:=0;
    str_id number := 30001;
    CURSOR CUR_DBMG_SAL_HEAD
    IS
    SELECT DSH.CM_NUMBER,D_DSH_CM_DATE, D_DSH_CM_TIME
    FROM DBMG_SAL_HEAD DSH
    WHERE ROWNUM<6;
    BEGIN
    OPEN CUR_DBMG_SAL_HEAD;
    LOOP
    FETCH CUR_DBMG_SAL_HEAD BULK COLLECT
    INTO V_DSH_CM_NUMBER,
    V_DSH_DATE,
    V_DSH_TIME;
    FOR indx IN V_DSH_CM_NUMBER.FIRST .. V_DSH_CM_NUMBER.LAST
    LOOP
    SELECT CM_NUMBER, PLU_CODE,V_DSH_DATE(indx)
    BULK COLLECT
    INTO V_DSD_CM_NUMBER, V_PLU_CODE,V_DSD_DATE
    FROM DBMG_SAL_DETL DSD
    WHERE DSD.CM_NUMBER = V_DSH_CM_NUMBER(indx);
    --block1
    /*Ln_Itm := 0;
    FOR ind IN 1..V_DSD_CM_NUMBER.COUNT
    loop
    INSERT INTO PC_ALL_TAB
    VALUES(V_DSH_CM_NUMBER(indx),
    V_DSD_DATE(ind),
    V_DSD_CM_NUMBER(ind),
    V_PLU_CODE(ind),
    LN_ITM,
    str_id
    LN_ITM := LN_ITM +1;
    end loop; */
    FORALL ind IN 1..V_DSD_CM_NUMBER.COUNT
    INSERT INTO PC_ALL_TAB
    VALUES(V_DSH_CM_NUMBER(indx),
    V_DSD_DATE(ind),
    V_DSD_CM_NUMBER(ind),
    V_PLU_CODE(ind),
    LN_ITM,
    str_id
    LN_ITM := LN_ITM +1;
    --block2                 
    END LOOP;
    EXIT WHEN CUR_DBMG_SAL_HEAD%NOTFOUND;
    END LOOP;
    commit;
    CLOSE CUR_DBMG_SAL_HEAD;
    DBMS_OUTPUT.PUT_LINE('COMPLETE..!');
    END ;
    o/p :- SELECT DSH_CM_NUMBER, LN_ITM FROM PC_ALL_TAB;
    DSH_CM_NUMBER     LN_ITM
    1     4177424           0
    2     4177422           1
    3     4177426           2
    4     4177426           2
    5     4177426           2
    6     4177425           3
    7     4177427           4
    8     4177427           4
    9     4177427           4
    I need result as below...but using "FORALL"
    DSH_CM_NUMBER     LN_ITM
    1     4177424     0
    2     4177422     0
    3     4177426     0
    4     4177426     1
    5     4177426     2
    6     4177425     0
    7     4177427     0
    8     4177427     1
    9     4177427     2

    Double post
    How to increment value using "FORALL" instead of for loop

  • For loop in forall

    Hi all
    i have a problem.Actually i'm giving a test problem here.While executing this i'm getting ora 66550 error .What wrong i'm doing?
    say col1 and col2 is column of tab1.
    type test is table of number;
    a_test test:=test(8,9);
    cursor c1(test number) is
    select col1 from tab1
    where col2=test;
    p1 c1%rowtype;
    begin
    forall i in 1 .. a_test.count
    for p1 in c1(a_test(i)) loop
    insert into b_test values(a_test(i),p1.col1)
    end loop;
    end;
    Thanks in advance

    bp wrote:
    Hi all
    i have a problem.Actually i'm giving a test problem here.While executing this i'm getting ora 66550 error .What wrong i'm doing?
    say col1 and col2 is column of tab1.
    type test is table of number;
    a_test test:=test(8,9);
    cursor c1(test number) is
    select col1 from tab1
    where col2=test;
    p1 c1%rowtype;
    begin
    forall i in 1 .. a_test.count
    for p1 in c1(a_test(i)) loop
    insert into b_test values(a_test(i),p1.col1)
    end loop;
    end;
    test@ORA10G>
    test@ORA10G>
    test@ORA10G> select * from tab1;
    C       COL2
    a          6
    b          7
    c          8
    d          9
    e         10
    5 rows selected.
    test@ORA10G>
    test@ORA10G>
    test@ORA10G> --
    test@ORA10G> declare
      2    type test is table of number;
      3    a_test test:=test(8,9);
      4  begin
      5    forall i in 1 .. a_test.count
      6      insert into b_test (x,y)
      7      select col2, col1
      8        from tab1
      9       where col2 = a_test(i);
    10  end;
    11  /
    PL/SQL procedure successfully completed.
    test@ORA10G>
    test@ORA10G> select * from b_test;
             X Y
             8 c
             9 d
    2 rows selected.
    test@ORA10G>
    test@ORA10G>isotope

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

Maybe you are looking for

  • Used Photoshop Image processor to batch convert from CR2 to Jpeg and the edits don't stick

    Ok, so I had a huge wedding where the bride paid me to deliver a ton of images.  Well, i did all my edits in ACR and then photoshop.  While in photoshop all the edits look to have been applied.  So, I use edit > Scripts>Image processor to convert the

  • Getting blue question mark for images in Safari

    Hi guys I have MBP 15", early 2011, 250 GB SSD, 16 GB RAM, 10.10 Yosemite OSx and I am facing problem recently is that some images in Safari 8 browser won't open and instead blue question mark will arise . I have friend of mine using ipad2 and I aske

  • Remove Payment Method Country Specific

    Hi Gurus, Is it possible to delete unnecessary Payment Methods in FBZP specific for one country? What are the impacts if this is removed if any? Any input is welcome Regards Roger

  • Restoration of back up data

    Hi, I have the back up of the enitre hyperion folder from my production env for a Planning application. I have replaced the Plan1 folder from the Prod env to the Dev env with the application I created in Essbase having a different name but the same d

  • Delivery document type settings

    Hi all, In standard SAP For LF delivery type, Default order type DL (Delivery with out sales order reference) is assigned.What is the use of this. For delivery with out reference to sales order system will not allow us to use delivery type LF. we onl