CodeSnip: Practical Use of "for update of" in Oracle Cursor
 
Published: 07 Feb 2008
Abstract
In this article, Deepankar examines the usage and application of the "for update of" cursor using Oracle 9i. He examines the concept with the help of a sample scenario. Initially, he provides the complete code listing followed by a detailed explanation. He finishes the discussion by examining the structure of the tables before and after coupon merging with the help of relevant screen captures.
by Deepankar Sarangi
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 25234/ 54

Introduction

This code snip explains how to update the coupon field of more than one table, using data from a coupon table using "for update of" cursor. The condition is that:

1. No coupon can be used more than once from coupon table.

2. Coupons being valuable entity should not be tampered by any DML operation during merging into target table.

This scenario occurs when we are given with some coupon codes stored in a coupon table. The records from this table will be used to update certain tables one after the other. So the coupon table maintains a flag showing which coupons have already been used once and uses only those records, which are not yet been used.

For safety reasons the coupon field in person_table_1 are locked through explicit locking by "for update of" clause to deny access for the duration of a tractions.

Requirements

Oracle 9i or above versions

Working

Let us examine the following code.

Listing 1

CREATE OR REPLACE
procedure multiple_table_update
   as
      /* Declaring variables*/
   v_coupon_id                  varchar2(15);
   validate_coupon_count        number;
   low_count_error              EXCEPTION;
   Live_coupons_left            number;
   coupons_used                 number;
   coupons_merged               number;
   count_original_coupons       number;
   count_persons                number;
   Error_code                   varchar2(400);
   Error_message                varchar2(400);
   
      /* declaring cursor for setting explicit locking on 
         coupon field before the updating*/
   cursor  cur_person 
   is 
   select person_id,coupon from person_table_1 where coupon is NULL
   for update of coupon;
   
      /* declaring cursor for selecting unused coupons one at a time */
   cursor cur_coupon
   is
   select coupon_id from coupon_table
   where flag ='N' and rownum = 1;
 
 
  begin
       /* Selecting the number of coupons before merging */
    select count(coupon_id) into count_original_coupons 
from coupon_table where    flag='N';
dbms_output.put_line(count_original_coupons||
' number of coupons present before merging');
    
    /* Selecting the number of coupons required before merging */
    select count(PERSON_ID) into count_persons from person_table_1;
    dbms_output.put_line(count_persons||' number of Persons to be merged');
    
    /* if number of coupons found less than required, control passes 
        to user defined exception */
select (count_original_coupons - count_persons) 
into validate_coupon_count from dual;
    if
        validate_coupon_count < 0 then
        RAISE low_count_error;
    Else
        /*coupon merging started */
        dbms_output.put_line('coupon merging started');
        /*open cur_ person cursor */
        for person_rec in cur_person
        loop
          
         /*open, fetch and direct first coupon in coupon_table in to a variable*/
    open cur_coupon;
          fetch cur_coupon into v_coupon_id;
          close cur_coupon;
          
/*update current row of person_table_1 table by putting the coupon in to it*/
          update person_table_1
          set coupon = v_coupon_id
          where current of cur_person;
 
           /*mark used coupon by setting flag to ‘Y’ so can’t be used again*/
          update coupon_table set flag='Y'
          where coupon_id=v_coupon_id;
 
          dbms_output.put_line(v_coupon_id||' '||cur_person%rowcount||
            ' Coupon fetched  '||'merged  '||'and Flag Updated ');
          
        end loop;
        
select count(coupon_id) into Live_coupons_left from coupon_table where flag='N';
        select count(coupon) into coupons_merged from person_table_1;
 
        dbms_output.put_line(coupons_merged||'Coupons merged successfully and '||
          Live_coupons_left||' coupons left');
    end if;
    commit;
 
   EXCEPTION 
          /*Catching exception for insufficient coupons*/
      WHEN low_count_error then
      dbms_output.put_line('Failed due to Insufficient coupons');    
      WHEN OTHERS then
      /*Catching exception for other reasons and rolling back incomplete merge*/
           Rollback;
      Error_message:=SQLERRM;
      Error_code:=SQLCODE;
     dbms_output.put_line('Failed due to '||Error_message|| 
        '  having error code'||Error_code ); 
      
  
end multiple_table_update;
Explanation

Here we are trying to update the coupon field of person_table_1 table by using the coupons from coupon_id field of coupon_table table. So we are required to hold the coupon field of person_table_1 and coupon_id field of coupon_table simultaneously.

In order to avoid any tampering of coupons while merging in to person_table_1, a lock has been set on coupon column protecting against any accidental DML operations. Care has been taken so that in case of in sufficient number of coupons no merging is done. In that case, control passes into user exception for catching.

When the loop runs for first time a coupon from coupon table flows in to a variable. Then by using the "current of" cursor the coupon is merged into first coupon field of person_table_1 table. Then the used coupon’s status has been set to "Y" in coupon_table after being merged successfully. Loop continues until all the coupons in person_table_1 table are updated.

When all the coupons are merged successfully "commit" is done. Commit frees the lock set upon the coupon field of person_table_1. In case of any other errors that may happen in between, they could be handled by "when others" and rollback is done to cancel incomplete merge.

Structures of tables before coupon merging is done

PERSON_TABLE_1 (contains 20 person_id) before merging.

Figure 1

COUPON_TABLE (contains 21 unmerged coupons with status "N")

Figure 2

Executing the procedure

Listing 2

Exec multiple_table_update;

Figure 3

Structures of tables after coupon merging is done

PERSON_TABLE_1 after merging.

Figure 4

COUPON_TABLE (contains 1 live coupon with status "N")

Figure 5

Conclusion

This code snip demonstrates the practical use of "for update of" and "current of" facilities in oracle. "For update of" puts a lock on the column mentioned in the select statement. As a result, the column is locked during the updating of that column.

During the coupon merging, the coupons of the current of clauses hold that record to be updated which is being pointed by the cursor.



User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-24 12:56:07 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search