說明:本內容是工作用到的知識點整理,來自工作中和網絡。
代碼於Oracle9上測試。
Oracle顯式游標和隱式游標
SQL是用於訪問Oracle數據庫的語言,PL/SQL擴展和加強了SQL的功能,它同時引入了更強的程序邏輯, 下面在本文中將對游標的使用進行一下講解,希望可以和大家共同學習進步。
游標字面理解就是游動的光標。游標是SQL的一個內存工作區,由系統或用戶以變量的形式定義。在某些情況下,需要把數據從存放在磁盤的表中調到計算機內存中進行處理,最后將處理結果顯示出來或最終寫回數據庫。這樣數據處理的速度才會提高,否則頻繁的磁盤數據交換會降低效率。用數據庫語言來描述游標就是映射在結果集中一行數據上的位置實體,有了游標,用戶就可以訪問結果集中的任意一行數據了,將游標放置到某行后,即可對該行數據進行操作,例如提取當前行的數據等。
游標有兩種類型:顯式游標和隱式游標。游標一旦打開,數據就從數據庫中傳送到游標變量中,然后應用程序再從游標變量中分解出需要的數據,並進行處理。
當系統使用一個隱式游標時,可以通過隱式游標的屬性來了解操作的狀態和結果,進而控制程序的流程。隱式游標可以使用名字SQL來訪問,但要注意,通過SQL游標名總是只能訪問前一個處理操作或單行SELECT操作的游標屬性。所以通常在剛剛執行完操作之后,立即使用SQL游標名來訪問屬性。游標的屬性有四種,分別是SQL %ISOPEN,SQL %FOUND,SQL %NOTFOUND,SQL %ROWCOUNT。
SQL%ISOPEN返回的類型為布爾型,判斷游標是否被打開,如果打開%ISOPEN等於true,否則等於false,即執行過程中為真,結束后為假。
SQL%NOTFOUND返回值為布爾型,判斷游標所在的行是否有效,如果有效,則%FOUNDD等於true,否則等於false,即與%FOUND屬性返回值相反。
SQL%FOUND返回值的類型為布爾型,值為TRUE代表插入 刪除 更新或單行查詢操作成功。
SQL%ROWCOUNT返回值類型為整型,返回當前位置為止游標讀取的記錄行數,即成功執行的數據行數。 示例代碼如下:
set serveroutput on;
declare
varno varchar2(20);
varprice varchar2(20);
CURSOR mycur(vartype number) is
select emp_no,emp_zc from cus_emp_basic
where com_no = vartype;
begin
if mycur%isopen = false then
open mycur(043925);
end if;
fetch mycur into varno,varprice;
while mycur%found
loop
dbms_output.put_line(varno||','||varprice);
if mycur%rowcount=2 then
exit;
end if;
fetch mycur into varno,varprice;
end loop;
close mycur;
end;
記錄並不保存在數據庫中,它與變量一樣,保存在內存空間中,在使用記錄時候,要首先定義記錄結構,然后聲明記錄變量。可以把PL/SQL記錄看作是一個用戶自定義的數據類型。
游標for循環是顯示游標的一種快捷使用方式,它使用for循環依次讀取結果集中的行數據,當form循環開始時,游標自動打開(不需要open),每循環一次系統自動讀取游標當前行的數據(不需要fetch),當退出for循環時,游標被自動關閉(不需要使用close)。使用游標for循環的時候不能使用open語句,fetch語句和close語句,否則會產生錯誤。declare
cursor mycur(vartype number)is
select emp_no,emp_zc from cus_emp_basic
where com_no=vartype;
begin
for person in mycur(000627) loop
dbms_output.put_line('編號:'||person.emp_no||',住址:'||person.emp_zc);
end loop;
end;
顯式游標的使用總共分4個步驟:
1.聲明游標
在DECLEAR部分按以下格式聲明游標:
CURSOR 游標名[(參數1 數據類型[參數2 數據類型...])]
IS SELECT語句;
參數是可選部分,所定義的參數可以出現在SELECT語句的WHERE子句中。如果定義了參數,則必須在打開游標時傳遞相應的實際參數。
SELECT語句是對表或視圖的查詢語句,甚至也可以是聯合查詢。可以帶WHERE條件、ORDER BY或GROUP BY等子句,但不能使用INTO子句。在SELECT語句中可以使用在定義游標之前定義的變量。
例:
DELCARE
CURSOR C_EMP IS SELECT empno,ename,salary
FROM emp WHERE salary>1500
ORDER BY ename;
........
BEGIN
在游標定義中SELECT語句中不一定非要表可以是視圖,也可以從多個表或視圖中選擇.
2.打開游標
使用游標中的值之前應該首先打開游標,打開游標初始化查詢處理。打開游標的語法
OPEN 游標名[(實際參數1[實際參數2,...])];
打開游標時,SELECT語句的查詢結果就被傳送到了游標工作區。
例:
OPEN C_EMP;
3.提取數據
從游標得到一行數據使用FETCH命令。每一次提取數據后,游標都指向結果集的下一
FETCH cursor_name INTO variable[,variable,...]
對於SELECT定義的游標的每一列,FETCH變量列表都應該有一個變量與之相對應,變
在可執行部分,按以下格式將游標工作區中的數據取到變量中。提取操作必須在打開游標之后進行。
FETCH 游標名 INTO 變量名1[變量名2,...];
或
FETCH 游標名 INTO 記錄變量;
游標打開后有一個指針指向數據區,FETCH語句一次返回指針所指的一行數據,要返回多行需重復執行,可以使用循環語句來實現。控制循環可以通過判斷游標的屬性來進行。
下面對這兩種格式進行說明:
第一種格式中的變量名是用來從游標中接收數據的變量,需要事先定義。變量的個數和類型應與SELECT語句中的字段變量的個數和類型一致。
第二種格式一次將一行數據取到記錄變量中,需要使用%ROWTYPE事先定義記錄變量,這種形式使用起來比較方便,不必分別定義和使用多個變量。
定義記錄變量的方法如下:
變量名 表名|游標名%ROWTYPE;
其中的表必須存在,游標名也必須先定義。
4.關閉游標
CLOSE 游標名;
例:
CLOSE C_EMP;
顯式游標打開后,必須顯式地關閉。游標一旦關閉,游標占用的資源就被釋放,游標變成無效,必須重新打開才能使用。
Oracle支持動態SELECT語句和動態游標,動態的方法大大擴展了程序設計的能力。
對於查詢結果為一行的SELECT語句,可以用動態生成查詢語句字符串的方法,在程序執行階段臨時地生成並執行,語法是:
execute immediate 查詢語句字符串 into 變量1[,變量2,...];
在變量聲明部分定義的游標是靜態的,不能在程序運行過程中修改。雖然可以通過參數傳遞來取得不同的數據,但還是有很大的局限性。通過采用動態游標,可以在程序運行階段隨時生成一個查詢語句作為游標。要使用動態游標需要先定義一個游標類型,然后聲明一個游標變量,游標對應的查詢語句可以在程序的執行過程中動態地說明。
Oracle帶參數游標
例子
DECLARE
dept_code emp.deptno%TYPE; --聲明列類型變量三個
emp_code emp.empno%TYPE;
emp_name emp.ename%TYPE;
CURSOR emp_cur(deptparam NUMBER) IS
SELECT empno, ename FROM EMP WHERE deptno = deptparam; --聲明顯示游標
BEGIN
dept_code := &部門編號; --請用戶輸入想查看的部門編號
OPEN emp_cur(dept_code); --打開游標
LOOP
--死循環
FETCH emp_cur
INTO emp_code, emp_name; --提取游標值賦給上面聲明的變量
EXIT WHEN emp_cur%NOTFOUND; --如果游標里沒有數據則退出循環
DBMS_OUTPUT.PUT_LINE(emp_code || '' || emp_name); --輸出查詢
END LOOP;
CLOSE emp_cur; --關閉游標
END;
Oracle 引用游標
ACCEPT tab FROMPT '你想查看什么信息?員工(E)或部門信息(D):'; --使用ACCEPT命令彈出對話框讓用戶輸入數據
DECLARE
TYPE refcur_t IS REF CURSOR; --聲明REF游標類型
refcur refcur_t; --聲明REF游標類型的變量
pid NUMBER;
p_name VARCHAR2(100);
selection VARCHAR2(1) := UPPER(SUBSTR('&tab', 1, 1)); --截取用戶輸入的字符串並轉換為大寫
BEGIN
IF selection = 'E' THEN
--如果輸入的是'E',則打開refcurr游標,並將員工表查詢出來賦值給此游標
OPEN refcur FOR
SELECT EMPNO ID, ENAME NAME FROM EMP;
DBMS_OUTPUT.PUT_LINE('=====員工信息=====');
ELSIF selection = 'D' THEN
--如果輸入是'D',則打開部門表
OPEN refcur FOR
SELECT deptno id, dname name FROM DEPT;
DBMS_OUTPUT.PUT_LINE('=====部門信息======');
ELSE
--否則返回結束
DBMS_OUTPUT.PUT_LINE('請輸入員工信息(E)或部門信息(D)');
RETURN;
END IF;
FETCH refcur
INTO pid, p_name; --提取行
WHILE refcur%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('#' || pid || ':' || p_name);
FETCH refcur
INTO pid, p_name;
END LOOP;
CLOSE refcur; --關閉游標
END;
Oracle 動態游標
VARIABLE maxsal NUMBER; --聲明變量
EXECUTE :maxsal := 2500; --執行引用並給變量賦值
DECLARE
r_emp EMP%ROWTYPE; --聲明一個行類型變量
TYPE c_type IS REF CURSOR; --聲明REF游標類型
cur c_type; --聲明REF游標類型的變量
p_salary NUMBER; --聲明一個標量變量
BEGIN
p_salary := :maxsal; --引用變量
--使用USING語句將引用到的值傳給動態SQL語句'SAL >: 1'中的'1'
OPEN cur FOR 'SELECT * FROM EMP WHERE SAL >: 1 ORDER BY SAL DESC'
USING p_salary;
DBMS_OUTPUT.PUT_LINE('薪水大於' || p_salary || '的員工有:');
LOOP
FETCH cur
INTO r_emp;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('編號:' || r_emp.empno || '姓名:' || r_emp.ename ||
'薪水:' || r_emp.sal);
END LOOP;
CLOSE cur; --關閉游標
END;