bulk collect using “for update”

后端 未结 2 2070
遇见更好的自我
遇见更好的自我 2021-01-06 13:32

I run into an interesting and unexpected issue when processing records in Oracle (11g) using BULK COLLECT.

The following code was running great, processing through

2条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-06 14:30

    Adding to Justin's Explantion.

    You should have seen the below error message.Not sure, if your Exception handler suppressed this.

    And the message itself explains a Lot!

    For this kind of Updates, it is better to create a shadow copy of the main table, and let the public synonym point to it. While some batch id, creates a private synonym to our main table and perform the batch operations, to keep it simpler for maintenance.

    Error report -
    ORA-01002: fetch out of sequence
    ORA-06512: at line 7
    01002. 00000 -  "fetch out of sequence"
    *Cause:    This error means that a fetch has been attempted from a cursor
               which is no longer valid.  Note that a PL/SQL cursor loop
               implicitly does fetches, and thus may also cause this error.
               There are a number of possible causes for this error, including:
               1) Fetching from a cursor after the last row has been retrieved
               and the ORA-1403 error returned.
               2) If the cursor has been opened with the FOR UPDATE clause,
               fetching after a COMMIT has been issued will return the error.
               3) Rebinding any placeholders in the SQL statement, then issuing
               a fetch before reexecuting the statement.
    *Action:   1) Do not issue a fetch statement after the last row has been
               retrieved - there are no more rows to fetch.
               2) Do not issue a COMMIT inside a fetch loop for a cursor
               that has been opened FOR UPDATE.
               3) Reexecute the statement after rebinding, then attempt to
               fetch again.
    

    Also, you can change you Logic by Using rowid

    An Example for Docs:

    DECLARE
    -- if "FOR UPDATE OF salary" is included on following line, an error is raised
       CURSOR c1 IS SELECT e.*,rowid FROM employees e;
       emp_rec  employees%ROWTYPE;
    BEGIN
       OPEN c1;
       LOOP
         FETCH c1 INTO emp_rec; -- FETCH fails on the second iteration with FOR UPDATE
         EXIT WHEN c1%NOTFOUND;
         IF emp_rec.employee_id = 105 THEN
           UPDATE employees SET salary = salary * 1.05 WHERE rowid = emp_rec.rowid;
             -- this mimics WHERE CURRENT OF c1
         END IF;
         COMMIT;  -- releases locks
       END LOOP;
    END;
    /
    

    You have to fetch a record row by row!! update it using the ROWID AND COMMIT immediately . And then proceed to the next row!

    But by this, you have to give up the Bulk Binding option.

提交回复
热议问题