1. 程式人生 > 資料庫 >Oracle中游標的用法

Oracle中游標的用法

什麼是遊標?

①從表中檢索出結果集,從中每次指向一條記錄進行互動的機制。

②關係資料庫中的操作是在完整的行集合上執行的。

由 SELECT 語句返回的行集合包括滿足該語句的 WHERE 子句所列條件的所有行。由該語句返回完整的行集合叫做結果集。

應用程式,尤其是互動和線上應用程式,把完整的結果集作為一個單元處理並不總是有效的。

這些應用程式需要一種機制來一次處理一行或連續的幾行。而遊標是對提供這一機制的結果集的擴充套件。

遊標是通過遊標庫來實現的。遊標庫是常常作為資料庫系統或資料訪問 API 的一部分而得以實現的軟體,用來管理從資料來源返回的資料的屬性(結果集)。這些屬性包括併發管理、在結果集中的位置、返回的行數,以及是否能夠在結果集中向前和/或向後移動(可滾動性)。

遊標跟蹤結果集中的位置,並允許對結果集逐行執行多個操作,在這個過程中可能返回至原始表,也可能不返回至原始表。

換句話說,遊標從概念上講基於資料庫的表返回結果集。

由於它指示結果集中的當前位置 ,就像計算機螢幕上的游標指示當前位置一樣,“遊標”由此得名。

遊標有什麼作用?

①指定結果集中特定行的位置。

②基於當前的結果集位置檢索一行或連續的幾行。

③在結果集的當前位置修改行中的資料。

④對其他使用者所做的資料更改定義不同的敏感性級別。

⑤可以以程式設計的方式訪問資料庫。

 

一、遊標:

1、概念:

遊標的本質是一個結果集resultset,主要用來臨時儲存從資料庫中提取出來的資料塊。

二、遊標的分類:

1、顯式遊標:

由使用者定義,需要的操作:定義遊標、開啟遊標、提取資料、關閉遊標,主要用於對查詢語句的處理。

屬性:%FOUND %NOTFOUND %ISOPEN %ROWCOUNT

Example:列印emp表的員工資訊

DECLARE  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;  v_empno emp.empno%TYPE;  v_name emp.ename%TYPE;  v_job emp.job%TYPE; BEGIN  OPEN emp_cursor;  LOOP  FETCH emp_cursor INTO
v_empno,v_name,v_job;  DBMS_OUTPUT.PUT_LINE('員工號為:'||v_empno||'姓名是'||v_name||'職位:'||v_job);  EXIT WHEN emp_cursor%NOTFOUND;  END LOOP;  CLOSE emp_cursor; END;

這裡嚴格按照顯示遊標的書寫規則:DECLARE emp_cursor定義遊標OPEN emp_cursor開啟遊標FETCH emp_cursor INTO...提取資料CLOSE emp_cursor關閉遊標,因為提取出來的資料屬於多行,所以通過loop迴圈列印即可。

Example2:檢驗遊標是否開啟,如果開啟顯示提取行數

DECLARE  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;  v_empno emp.empno%TYPE;  v_name emp.ename%TYPE;  v_job emp.job%TYPE; BEGIN  OPEN emp_cursor;  LOOP   FETCH emp_cursor INTO v_empno,v_name,v_job;   EXIT WHEN emp_cursor%NOTFOUND;  END LOOP;  IF emp_cursor%ISOPEN THEN  DBMS_OUTPUT.PUT_LINE('遊標已開啟');  DBMS_OUTPUT.PUT_LINE('讀取了'||emp_cursor%ROWCOUNT||'行');  ELSE  DBMS_OUTPUT.PUT_LINE('遊標沒有開啟');  END IF;  CLOSE emp_cursor; END;

 

 

 

 

-- 遊標(游標cursor)
--在寫Java程式中有集合的概念, 那麼在pl/sql中也會用到多條記錄, 這時候我們就要用到遊標, 遊標可以儲存查詢返回的多條資料。
-- 語法:cursor 遊標名(引數 資料型別,引數 資料型別) is select 語句;
-- 列如 cursor c1 is select ename from emp;
-- 遊標使用步驟
-- 開啟遊標:open c1
-- 取一行遊標值 fetch c1 into pjob;(取一行資料到變數中)
-- 關閉遊標 close c1
-- 遊標結束方式 exit when c1%notfound

-- 查詢姓名和工資
declare
cursor vrows is select * from emp;
vrow emp%Rowtype;
begin
open vrows;
loop
fetch vrows into vrow;
exit when vrows%notfound;
dbms_output.put_line('姓名:'||vrow.ename||' '||'工資:'||vrow.sal);
end loop;
close vrows;
end;

-- 指定部門下的員工工資
declare
cursor deptSal(dno number) is select * from emp where deptno=dno;
dep emp%rowtype;
begin
open deptSal(10);
loop
fetch deptSal into dep;
exit when deptSal%notfound;
dbms_output.put_line('員工姓名:'||dep.ename||' '||'工資:'||dep.sal);
end loop;
close deptSal;
end;
-- 引用系統遊標
declare
vrows sys_refcursor; -- 引用系統遊標
vrow emp%rowtype; -- 記錄一行資料
begin
open vrows for select * from emp;
loop
fetch vrows into vrow;
exit when vrows%notfound;
dbms_output.put_line('姓名:'||vrow.ename||' '||'工資:'||vrow.sal);
end loop;
close vrows;
end;

-- 使用for迴圈遍歷遊標
declare
-- 申明遊標
cursor vrows is select * from emp;
begin
for vrow in vrows loop
dbms_output.put_line('姓名為:'||vrow.ename||'工資為:'||vrow.sal);
end loop;
end;

-- 按員工的工種長工資,總裁1000元,經理長800元其, 他人員長400元
declare
cursor vrows is select * from emp;
vrow emp%rowtype;
begin
open vrows;
loop
fetch vrows into vrow;
exit when vrows%notfound;
if vrow.job='PRESIDENT' then
update emp set sal=sal+1000 where empno=vrow.empno;
elsif vrow.job='MANAGER' then
update emp set sal=sal+800 where empno=vrow.empno;
else
update emp set sal=sal+400 where empno=vrow.empno;
end if;
dbms_output.put_line('姓名為:'||vrow.ename||'工資為:'||vrow.sal);
end loop;
close vrows;
end;

2、隱式遊標:由系統定義併為它建立工作區域,並且隱式的定義開啟提取關閉,隱式遊標的遊標名就是'SQL',屬性和顯示遊標相同,主要用於對單行select語句或dml操作進行處理。Example:又使用者輸入員工號修改員工工資如成功則列印輸出成功標誌。

3、引數遊標:

在定義遊標時加入引數的遊標,可以配合遊標for迴圈快速找到需要的資料。這裡先講一下游標for迴圈

A、遊標FOR迴圈:

隱含的執行了開啟提取關閉資料,程式碼精簡很多。Expression:

FOR table_record IN table_cursor LOOP

  STATEMENT;

END LOOP;

三、使用遊標修改資料的注意事項

1、使用遊標修改資料時,為防止他人在自己操作資料時對資料進行修改,oracle提供for update子句進行加鎖。

同時在你使用update或delete時,必須使用where current of+name_cursor語句,以及在最後記得提交。如果是級聯操作則可以使用for update of 來進行相關表的加鎖。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

宣告遊標;CURSOR cursor_name IS select_statement

--For 循環遊標
--(1)定義遊標
--(2)定義遊標變數
--(3)使用for迴圈來使用這個遊標
declare
--型別定義
cursor c_job
is
select empno,ename,job,sal
from emp
where job='MANAGER';
--定義一個遊標變數v_cinfo c_emp%ROWTYPE ,該型別為遊標c_emp中的一行資料型別
c_row c_job%rowtype;
begin
for c_row in c_job loop
dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
end loop;
end;



--Fetch遊標
--使用的時候必須要明確的開啟和關閉

declare
--型別定義
cursor c_job
is
select empno,ename,job,sal
from emp
where job='MANAGER';
--定義一個遊標變數
c_row c_job%rowtype;
begin
open c_job;
loop
--提取一行資料到c_row
fetch c_job into c_row;
--判讀是否提取到值,沒取到值就退出
--取到值c_job%notfound 是false
--取不到值c_job%notfound 是true
exit when c_job%notfound;
dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
end loop;
--關閉遊標
close c_job;
end;

--1:任意執行一個update操作,用隱式遊標sql的屬性%found,%notfound,%rowcount,%isopen觀察update語句的執行情況。
begin
update emp set ENAME='ALEARK' WHERE EMPNO=7469;
if sql%isopen then
dbms_output.put_line('Openging');
else
dbms_output.put_line('closing');
end if;
if sql%found then
dbms_output.put_line('遊標指向了有效行');--判斷遊標是否指向有效行
else
dbms_output.put_line('Sorry');
end if;
if sql%notfound then
dbms_output.put_line('Also Sorry');
else
dbms_output.put_line('Haha');
end if;
dbms_output.put_line(sql%rowcount);
exception
when no_data_found then
dbms_output.put_line('Sorry No data');
when too_many_rows then
dbms_output.put_line('Too Many rows');
end;
declare
empNumber emp.EMPNO%TYPE;
empName emp.ENAME%TYPE;
begin
if sql%isopen then
dbms_output.put_line('Cursor is opinging');
else
dbms_output.put_line('Cursor is Close');
end if;
if sql%notfound then
dbms_output.put_line('No Value');
else
dbms_output.put_line(empNumber);
end if; dbms_output.put_line(sql%rowcount);