1. 程式人生 > >Oracle 引數 遊標[遊標更新刪除資料]

Oracle 引數 遊標[遊標更新刪除資料]

一、引數遊標
   引數遊標是帶有引數的遊標,在定義引數遊標之後,當使用不同引數值多次開啟遊標時,可以產生不同的結果集,語法如下:
cursor cursor_name(parameter_name datatype) is select_statement;
定義引數遊標時,遊標引數只能指定資料型別,而不能指定長度。
示例如下:

Oracle程式碼
1.declare  
2.cursor temp_cursor(no number) is select name from cip_temps where id=no;  
3.v_name cip_temps.name%type;   
4.begin  
5.open temp_cursor(1);  
6.loop  
7.fetch temp_cursor into v_name;  
8.exit when temp_cursor%notfound;  
9.dbms_output.put_line(v_name);  
10.end loop;  
11.close temp_cursor;  
12.end; 
declare
cursor temp_cursor(no number) is select name from cip_temps where id=no;
v_name cip_temps.name%type;
begin
open temp_cursor(1);
loop
fetch temp_cursor into v_name;
exit when temp_cursor%notfound;
dbms_output.put_line(v_name);
end loop;
close temp_cursor;
end;

二、使用遊標更新或刪除資料
通過使用顯示遊標,不僅可以一行一行的處理select語句結果,而且也可以更新或刪除當前遊標的資料,注意,如果要通過遊標更新或刪除資料,在定義遊標時一定要帶有for update子句,語法如下:
cursor cursor_name(parameter_name datatype) is select_statement for updae [of column_reference][nowait];如上所示:for update子句用於在遊標結果集資料上加行共享鎖,以防止其他使用者在相應行上執行DML操作,當select語句要引用到多張表是,使用of子句可以確定哪些表要加鎖,如果沒有of子句,則會在select語句所引用的全部表上加鎖,nowait用於指定不等待鎖,為了更新或刪除當前遊標行資料,必須在update 或delete語句中引用where current of 子句,語法如下:
update table_name set column=.. where current of cursor_name;
delete from table_name  where current of cursor_name;
1、使用遊標更新資料

Oracle程式碼
1.declare  
2.cursor temp_cursor is select name,address,id from cip_temps for update;  
3.v_name cip_temps.name%type;  
4.v_address cip_temps.ADDRESS%type;  
5.v_id cip_temps.id%type;  
6.begin  
7.open temp_cursor;  
8.loop  
9.fetch temp_cursor into v_name,v_address,v_id;  
10.exit when temp_cursor%NOTFOUND;  
11.if(v_id>4) then  
12.update cip_temps set name='name'||to_char(v_id),address='address'||to_char(v_id) where current of temp_cursor;  
13.end if;  
14.end loop;  
15.close temp_cursor;  
16.end; 
declare
cursor temp_cursor is select name,address,id from cip_temps for update;
v_name cip_temps.name%type;
v_address cip_temps.ADDRESS%type;
v_id cip_temps.id%type;
begin
open temp_cursor;
loop
fetch temp_cursor into v_name,v_address,v_id;
exit when temp_cursor%NOTFOUND;
if(v_id>4) then
update cip_temps set name='name'||to_char(v_id),address='address'||to_char(v_id) where current of temp_cursor;
end if;
end loop;
close temp_cursor;
end;

2、使用遊標刪除資料 

Oracle程式碼
1.declare  
2.cursor temp_cursor is select name,address,id from cip_temps for update;  
3.v_name cip_temps.name%type;  
4.v_address cip_temps.ADDRESS%type;  
5.v_id cip_temps.id%type;  
6.begin  
7.open temp_cursor;  
8.loop  
9.fetch temp_cursor into v_name,v_address,v_id;  
10.exit when temp_cursor%NOTFOUND;  
11.if(v_id>2) then  
12.delete from cip_temps where current of temp_cursor;  
13.end if;  
14.end loop;  
15.close temp_cursor;  
16.end; 
declare
cursor temp_cursor is select name,address,id from cip_temps for update;
v_name cip_temps.name%type;
v_address cip_temps.ADDRESS%type;
v_id cip_temps.id%type;
begin
open temp_cursor;
loop
fetch temp_cursor into v_name,v_address,v_id;
exit when temp_cursor%NOTFOUND;
if(v_id>2) then
delete from cip_temps where current of temp_cursor;
end if;
end loop;
close temp_cursor;
end;

3、使用of子句在特定表加行共享鎖。
如果使用子查詢涉及到多張表,那麼預設情況下會在所有表上加行共享鎖,為了只在特定表上加行共享鎖,需要在for update子句後帶有of子句,of後面跟欄位名,如果跟表名或遊標名稱,則會報錯:標示符無效。示例如下:

Oracle程式碼
1.declare  
2.cursor gData is select name,address,cip_temps.id from cip_temps,cip_t   
3.where cip_temps.id=cip_t.id for update  of address;  
4.rs gData%rowtype;  
5.begin  
6.  open gData;  
7.  loop  
8.     fetch gData into rs;  
9.     exit when gData%notfound;  
10.         if rs.id=1 then  
11.            delete from cip_temps where current of gData;   
12.         else  
13.            update cip_temps set name='塞北的雪' where current of gData;  
14.         end if;  
15.    
16.  end loop;  
17.  close gData;  
18.end; 
declare
cursor gData is select name,address,cip_temps.id from cip_temps,cip_t
where cip_temps.id=cip_t.id for update  of address;
rs gData%rowtype;
begin
  open gData;
  loop
     fetch gData into rs;
     exit when gData%notfound;
         if rs.id=1 then
            delete from cip_temps where current of gData;
         else
            update cip_temps set name='塞北的雪' where current of gData;
         end if;
 
  end loop;
  close gData;
end;

4、使用nowait子句
使用for update語句對被作用於行加鎖,如果其他會話已經在被作用於行上加鎖,那麼預設情況下當前會話要一直等待對方釋放鎖,通過在for update子句中指定 nowait語句,可以避免等待鎖,當指定了nowait子句之後,如果其他會話已經在被作用行加鎖,那麼當前會話會顯示錯誤提示資訊,並退出PL/SQL,示例如下:

Oracle程式碼
1.declare  
2.cursor gData is select name,address,cip_temps.id from cip_temps,cip_t   
3.where cip_temps.id=cip_t.id for update  nowait;  
4.rs gData%rowtype;  
5.begin  
6.  open gData;  
7.  loop  
8.     fetch gData into rs;  
9.     exit when gData%notfound;  
10.         if rs.id=1 then  
11.            delete from cip_temps where current of gData;   
12.         else  
13.            update cip_temps set name='塞北的雪' where current of gData;  
14.         end if;  
15.    
16.  end loop;  
17.  close gData;  
18.end; 
declare
cursor gData is select name,address,cip_temps.id from cip_temps,cip_t
where cip_temps.id=cip_t.id for update  nowait;
rs gData%rowtype;
begin
  open gData;
  loop
     fetch gData into rs;
     exit when gData%notfound;
         if rs.id=1 then
            delete from cip_temps where current of gData;
         else
            update cip_temps set name='塞北的雪' where current of gData;
         end if;
 
  end loop;
  close gData;
end;

三、遊標for迴圈
   使用遊標for迴圈是循環遊標最簡單的方法,oracle會隱含開啟遊標、迴圈提取資料、關閉遊標,語法如下:
     for record_name  in cursor_name  loop
           ..........
     end loop;
如上所示:cursor_name是已經定義的遊標名稱,record_name是oracle隱含定義的記錄變數。
1、使用遊標for迴圈
   當使用遊標開發程式時,建議使用for迴圈,從而簡化程式碼程式,示例如下:

Oracle程式碼
1.declare  
2.cursor temp_cursor is  select name,age,address,id from cip_temps;  
3.begin  
4.for emp_record in temp_cursor loop  
5.dbms_output.put_line(temp_cursor%rowcount||'第一行資料:'||emp_record.name||':'|| emp_record.age||':'||  emp_record.address||':'|| emp_record.id);  
6.end loop;  
7.end; 
declare
cursor temp_cursor is  select name,age,address,id from cip_temps;
begin
for emp_record in temp_cursor loop
dbms_output.put_line(temp_cursor%rowcount||'第一行資料:'||emp_record.name||':'|| emp_record.age||':'||  emp_record.address||':'|| emp_record.id);
end loop;
end;

2、在遊標for迴圈時直接使用子查詢

Sql程式碼
1.declare     
2.begin     
3.for emp_record in (select * from cip_temps) loop     
4.dbms_output.put_line('第一行資料:'||emp_record.name||':'|| emp_record.age||':'||  emp_record.address||':'|| emp_record.id);     
5.end loop;     
6.end;