1. 程式人生 > 其它 >Oracle資料庫的遊標和for迴圈使用 Oracle資料庫的遊標和for迴圈使用

Oracle資料庫的遊標和for迴圈使用 Oracle資料庫的遊標和for迴圈使用

Oracle資料庫的遊標和for迴圈使用

 

 

1. 遊標的概念和作用

  • 遊標是 sql 的一個記憶體工作區,由系統或使用者以變數的形式定義
  • 遊標的作用就是用於臨時儲存從資料庫中提取的資料塊(結果集)。
  • 它有一個 指標,從上往下移動(fetch),從而能夠遍歷每條記錄。
  • 用 犧牲記憶體 來提升 SQL 執行效率,適用於 大資料處理。

    (摘抄自https://blog.csdn.net/qq_34745941/java/article/details/81294166)。 

2.遊標結構圖

 

 

 3.具體用法

  遊標有四大屬性,分別是

       1. “SQL%ISOPEN” :布林型別。判斷遊標是否開啟

  2.“SQL%FOUND”:布林型別。判斷上一條fetch語句是否有值,有則為true,否則為false;

  3.“SQL%NOTFOUND”:布林型別。與2相反,常用作退出迴圈的條件。

  4.“SQL%ROWCOUNT”:整型。當前成功執行更改的資料行數。

  3.1 靜態遊標

   3.1.1 隱式遊標

    使用DML操作(增刪改)或select……into……會自動建立隱式遊標,名稱是“sql”,該遊標會自動宣告,開啟和關閉。無需人為開啟或關閉。

    

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_id staff.id%type;
begin
  insert into staff(id,name) values(1,'張三');
  if sql%found then
     O_Result:='新增成功';
  end if;
     
  update staff set name = '李四'where id = 1;
  if sql%found then
     O_Result:='更新成功';
  end if;
  
  delete from staff where id = 1;
  if sql%found then
     O_Result:='刪除成功';
  end if;
  
  select id into v_id from staff;
  if sql%found then
     O_Result:='查詢成功';
  end if;
  
  if sql%isopen then
     O_Result:='遊標為開啟狀態,但不可能走到這一步';   --遊標只有在執行上述增刪改操作才會開啟並自動關閉
  else
     O_Result:='遊標為關閉狀態';
  end if;

exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

 

  3.1.2 顯式遊標

  顯示遊標又分為不帶引數和帶引數兩種

  無參:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 cursor v_cur is       --宣告遊標 為staff表的資料集
     select * from staff;
begin
      open v_cur; --開啟遊標
      
      fetch v_cur into v_cur_info; --賦值給遊標
      
       O_Result:='ID:'||v_cur_info.id||',Name:'||v_cur_info.name;--輸出值
      close v_cur; --關閉遊標

exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

輸出結果: ID:1,Name:張三

帶參:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 cursor v_cur(v_id staff.id%type) is       --宣告遊標 為staff表的資料集
     select * from staff where id =v_id;   --引數:v_id
begin
      open v_cur(1); --開啟遊標
      
      fetch v_cur into v_cur_info; --賦值給遊標
      
       O_Result:='ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      close v_cur; --關閉遊標

exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

輸出結果: ID:1,Name:張三

  3.2 動態遊標

  3.2.1 自定義型別遊標

    自定義遊標型別宣告寫法:

TYPE ref_type_name IS REF CURSOR

[RETURN return_type];

ref_type_name代表我們自定義型別的名稱,cursor是系統預設的

return_type代表資料庫表中的一行,或一個記錄型別,是一個返回型別;

返回值不是必要的,無返回值則稱為弱型別,更加靈活;有返回值稱為強型別,減少錯誤;

弱型別寫法:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 type v_cur_type is ref cursor;  --自定義遊標型別
 v_cur v_cur_type; 
begin
      open v_cur for             --開啟遊標並宣告
      select * from staff where id<5;
      loop                       --開始迴圈
        fetch v_cur into v_cur_info;    -- 賦值
        exit when v_cur%notfound;       --判斷沒有值就退出迴圈
        O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      end loop;
    close v_cur;  
exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

另一種寫法:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_sql varchar(1000);
 v_param staff.id%type:=5;
 v_cur_info staff%rowtype;
 type v_cur_type is ref cursor;  --自定義遊標型別
 v_cur v_cur_type; 
begin
  v_sql:='select * from staff where id <:id';
  
      open v_cur for v_sql            --開啟遊標並宣告
      using v_param;                  --繫結引數方法
      loop                       --開始迴圈
        fetch v_cur into v_cur_info;    -- 賦值
        exit when v_cur%notfound;       --判斷沒有值就退出迴圈
        O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      end loop;
    close v_cur;  
exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

強型別寫法:

    三個注意事項:

   1.強型別無法使用繫結引數方法

 2.for後面必須是sql,不能是字串,如上面的v_sql;

 3.引數必須對應;

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 type v_cur_type is ref cursor return staff%rowtype ;  --自定義遊標型別
 v_cur v_cur_type; 
begin
  
      open v_cur for  --開啟遊標並宣告
      select * from staff where id <5;           
      loop                       --開始迴圈
        fetch v_cur into v_cur_info;    -- 賦值
        exit when v_cur%notfound;       --判斷沒有值就退出迴圈
        O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      end loop;
    close v_cur;  
exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

  3.2.2 系統型別遊標

  簡寫手動宣告自定義遊標的過程

 type v_cur_type is ref cursor return staff%rowtype ;  --自定義遊標型別
 v_cur v_cur_type; 
等同於 v_cur sys_refcursor; 

4.效率問題

沒有實際測試過,根據其他部落格總結是這樣:一般來說批量處理的速度要最好,隱式遊標的次之,單條處理的最差

 以下是示例:

1、批量處理
open 遊標;
loop
   fetch 遊標 bulk collect into 集合變數(也就是 table 型別哦) limit 數值; -- 一般 500 左右
   exit when 條件 --(變數.count = 0,如果用 sql%notfound 不足 limit 的記錄就不會被執行哦)
close 遊標;

2、隱式遊標
for x in (sql 語句) loop
... 邏輯處理
end loop;

3、單條處理
open  遊標;
loop
   fetch 遊標 into 變數;
   exit when 條件
end loop;
close 遊標;
————————————————
原文連結:https://blog.csdn.net/qq_34745941/java/article/details/81294166

批量處理的關鍵字不是很瞭解,下次學習下在記錄起來;

隱式遊標寫法最簡潔明瞭,類似於程式中的for迴圈寫法;

單條處理大概就是上面那些範例的寫法。

 

1. 遊標的概念和作用

  • 遊標是 sql 的一個記憶體工作區,由系統或使用者以變數的形式定義
  • 遊標的作用就是用於臨時儲存從資料庫中提取的資料塊(結果集)。
  • 它有一個 指標,從上往下移動(fetch),從而能夠遍歷每條記錄。
  • 用 犧牲記憶體 來提升 SQL 執行效率,適用於 大資料處理。

    (摘抄自https://blog.csdn.net/qq_34745941/java/article/details/81294166)。 

2.遊標結構圖

 

 

 3.具體用法

  遊標有四大屬性,分別是

       1. “SQL%ISOPEN” :布林型別。判斷遊標是否開啟

  2.“SQL%FOUND”:布林型別。判斷上一條fetch語句是否有值,有則為true,否則為false;

  3.“SQL%NOTFOUND”:布林型別。與2相反,常用作退出迴圈的條件。

  4.“SQL%ROWCOUNT”:整型。當前成功執行更改的資料行數。

  3.1 靜態遊標

   3.1.1 隱式遊標

    使用DML操作(增刪改)或select……into……會自動建立隱式遊標,名稱是“sql”,該遊標會自動宣告,開啟和關閉。無需人為開啟或關閉。

    

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_id staff.id%type;
begin
  insert into staff(id,name) values(1,'張三');
  if sql%found then
     O_Result:='新增成功';
  end if;
     
  update staff set name = '李四'where id = 1;
  if sql%found then
     O_Result:='更新成功';
  end if;
  
  delete from staff where id = 1;
  if sql%found then
     O_Result:='刪除成功';
  end if;
  
  select id into v_id from staff;
  if sql%found then
     O_Result:='查詢成功';
  end if;
  
  if sql%isopen then
     O_Result:='遊標為開啟狀態,但不可能走到這一步';   --遊標只有在執行上述增刪改操作才會開啟並自動關閉
  else
     O_Result:='遊標為關閉狀態';
  end if;

exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

 

  3.1.2 顯式遊標

  顯示遊標又分為不帶引數和帶引數兩種

  無參:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 cursor v_cur is       --宣告遊標 為staff表的資料集
     select * from staff;
begin
      open v_cur; --開啟遊標
      
      fetch v_cur into v_cur_info; --賦值給遊標
      
       O_Result:='ID:'||v_cur_info.id||',Name:'||v_cur_info.name;--輸出值
      close v_cur; --關閉遊標

exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

輸出結果: ID:1,Name:張三

帶參:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 cursor v_cur(v_id staff.id%type) is       --宣告遊標 為staff表的資料集
     select * from staff where id =v_id;   --引數:v_id
begin
      open v_cur(1); --開啟遊標
      
      fetch v_cur into v_cur_info; --賦值給遊標
      
       O_Result:='ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      close v_cur; --關閉遊標

exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

輸出結果: ID:1,Name:張三

  3.2 動態遊標

  3.2.1 自定義型別遊標

    自定義遊標型別宣告寫法:

TYPE ref_type_name IS REF CURSOR

[RETURN return_type];

ref_type_name代表我們自定義型別的名稱,cursor是系統預設的

return_type代表資料庫表中的一行,或一個記錄型別,是一個返回型別;

返回值不是必要的,無返回值則稱為弱型別,更加靈活;有返回值稱為強型別,減少錯誤;

弱型別寫法:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 type v_cur_type is ref cursor;  --自定義遊標型別
 v_cur v_cur_type; 
begin
      open v_cur for             --開啟遊標並宣告
      select * from staff where id<5;
      loop                       --開始迴圈
        fetch v_cur into v_cur_info;    -- 賦值
        exit when v_cur%notfound;       --判斷沒有值就退出迴圈
        O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      end loop;
    close v_cur;  
exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

另一種寫法:

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_sql varchar(1000);
 v_param staff.id%type:=5;
 v_cur_info staff%rowtype;
 type v_cur_type is ref cursor;  --自定義遊標型別
 v_cur v_cur_type; 
begin
  v_sql:='select * from staff where id <:id';
  
      open v_cur for v_sql            --開啟遊標並宣告
      using v_param;                  --繫結引數方法
      loop                       --開始迴圈
        fetch v_cur into v_cur_info;    -- 賦值
        exit when v_cur%notfound;       --判斷沒有值就退出迴圈
        O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      end loop;
    close v_cur;  
exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

強型別寫法:

    三個注意事項:

   1.強型別無法使用繫結引數方法

 2.for後面必須是sql,不能是字串,如上面的v_sql;

 3.引數必須對應;

create or replace procedure ATest(
 O_Result  Out VarChar2
)is 
 v_cur_info staff%rowtype;
 type v_cur_type is ref cursor return staff%rowtype ;  --自定義遊標型別
 v_cur v_cur_type; 
begin
  
      open v_cur for  --開啟遊標並宣告
      select * from staff where id <5;           
      loop                       --開始迴圈
        fetch v_cur into v_cur_info;    -- 賦值
        exit when v_cur%notfound;       --判斷沒有值就退出迴圈
        O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name;
      end loop;
    close v_cur;  
exception
  when Others then
  begin
    O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM;
    rollback;
  end;
end;

  3.2.2 系統型別遊標

  簡寫手動宣告自定義遊標的過程

 type v_cur_type is ref cursor return staff%rowtype ;  --自定義遊標型別
 v_cur v_cur_type; 
等同於 v_cur sys_refcursor; 

4.效率問題

沒有實際測試過,根據其他部落格總結是這樣:一般來說批量處理的速度要最好,隱式遊標的次之,單條處理的最差

 以下是示例:

1、批量處理
open 遊標;
loop
   fetch 遊標 bulk collect into 集合變數(也就是 table 型別哦) limit 數值; -- 一般 500 左右
   exit when 條件 --(變數.count = 0,如果用 sql%notfound 不足 limit 的記錄就不會被執行哦)
close 遊標;

2、隱式遊標
for x in (sql 語句) loop
... 邏輯處理
end loop;

3、單條處理
open  遊標;
loop
   fetch 遊標 into 變數;
   exit when 條件
end loop;
close 遊標;
————————————————
原文連結:https://blog.csdn.net/qq_34745941/java/article/details/81294166

批量處理的關鍵字不是很瞭解,下次學習下在記錄起來;

隱式遊標寫法最簡潔明瞭,類似於程式中的for迴圈寫法;

單條處理大概就是上面那些範例的寫法。