Oracle遊標詳解
1、遊標的概念
遊標(CURSOR):遊標是把從資料表中提取出來的資料,以臨時表的形式存放在記憶體中,在遊標中有一個數據指標,在初始狀態下指向的是首記錄,利用fetch語句可以移動該指標,從而對遊標中的資料進行各種操作。
2、遊標的作用
遊標是用來處理使用SELECT語句從資料庫中檢索到的多行記錄的工具。藉助於遊標的功能,資料庫應用程式可以對一組記錄逐條進行處理,每次處理一行。
3、遊標的型別
- 顯式遊標(Explicit Cursor):顯式遊標需要定義宣告,在使用前要開啟和獲取,使用完畢後要關閉。多用於返回多行的SELECT語句
- 隱式遊標(Implicit Cursor):在執行一個SQL語句時,伺服器將自動建立一個隱式遊標,該遊標是記憶體中的工作區,儲存了執行SQL語句的結果,可通過遊標的屬性獲得SQL的執行結果及狀態資訊。多用於只返回一行的SQL語句
4、隱式遊標
(ORACLE在建立隱式遊標時,預設的遊標名為SQL)
1)遊標的主要屬性(顯示遊標、隱式遊標)
- %FOUND 布林型屬性,當SQL語句至少影響一行時為TRUE,否則為FALSE
- %NOTFOUND 布林型屬性,當SQL語句沒有影響的行時為TRUE,否則為FALSE
- %ISOPEN 布林型屬性,當遊標已開啟時返回TRUE,否則為FALSE(對使用者而言,隱式遊標永遠是false)
- %ROWCOUNT 數 字型屬性,返回受到SQL影響的行數
注意:
屬性名與遊標名之間沒有空格。
遊標的屬性只能在PL/SQL塊中使用,而不能在SQL語句中使用
例1 將PRODUCTS表中型別為1的所有產品的單價打9折,並顯示該更新所影響的行數.
BEGIN UPDATE products SET unitprice=unitprice*0.9 WHERE categoryid=1; IF SQL%FOUND THEN dbms_output.put_line(‘更新了’||SQL%ROWCOUNT||’條記錄’); ELSE dbms_output.put_line(‘沒有更新記錄’); END IF; END;
5、顯式遊標
1)定義遊標
在使用顯示遊標之前,必須先在宣告部分定義遊標,其定義語法如下:
CURSOR cursor_name[(parameter,…)]
說明: 引數parameter形式如下:
para_name [IN] data_type [:=|DEFAULT value]
(2)開啟遊標
當開啟遊標時,ORACLE會執行遊標所對應的SELECT語句,並將結果存放到結果集,其定義語法如下:
OPEN cursor_name[(parameter,…)];
(3)提取資料語法如下:
FETCH cursor_name INTO variable[,…];
說明:
對遊標第一次執行FETCH語句時,它將工作區中的第一條記錄賦給賦給變數,並使工作區內的指標指向下一條記錄。
工作區中的遊標指標只能向下移動,不能回退。
在使用FETCH語句之前,必須先開啟遊標,才能保證工作區內有資料。
INTO子句中的變數,順序、型別必須與工作區中每行記錄的欄位數、順序以及資料型別一一對應
(4)關閉遊標
關閉遊標可釋放其結果集,語法如下:
CLOSE cursor_name;
說明:關閉遊標,就是使遊標所對應的記憶體工作區變為無效,並釋放與遊標相關的系統資源
例3:用顯式遊標顯示輸出products表中供應商編號為6 的產品的資訊。
DECLARE
CURSOR prod_cursor IS
select *from products where
supplierid=6;
prod_record products%rowtype;
BEGIN
OPEN prod_cursor;
LOOP
FETCH prod_cursor INTO prod_record;
EXIT WHEN
prod_cursor%NOTFOUND;
dbms_output.put_line(‘產品編號’||prod_record.productid);
dbms_output.put_line(‘產品名稱’||prod_record.productname);
dbms_output.put_line(‘供應商編號’||prod_record.supplierid);
END LOOP;
CLOSE prod_cursor;
END;
例4:用顯式引數遊標顯示輸出products表中供應商編號為XX 的產品的資訊。
DECLARE
CURSOR prod_cursor (suppID in number DEFAULT 1) IS
select * from products where
supplierid=suppId;
prod_record products%rowtype;
BEGIN
OPEN prod_cursor(2);
LOOP
FETCH prod_cursor INTO prod_record;
EXIT WHEN
prod_cursor%notfound;
dbms_output.put_line(‘產品編號’||prod_record.productid);
dbms_output.put_line(‘產品名稱’||prod_record.productname);
dbms_output.put_line(‘供應商編號’||prod_record.supplierid);
END LOOP;
CLOSE prod_cursor;
END;
注意:在為引數遊標定義引數的資料型別時,不能使用長度約束
顯式遊標——遊標FOR迴圈
語法格式:
FOR 迴圈變數 IN 遊標型別名
LOOP
迴圈語句
END LOOP;
注意:
迴圈變數不需要定義,系統隱含地定義其資料型別為%ROWTYPE的變數
使用遊標FOR迴圈時,不能使用OPEN、FETCH、CLOSE語句。
例5:用顯式引數遊標顯示輸出products表中供應商編號為XX 的產品的資訊。
DECLARE
CURSOR prod_cursor (suppID in number DEFAULT 1) IS
select *from products where supplierid=suppId;
BEGIN
FOR v_pr IN prod_cursor(3) LOOP
dbms_output.put_line(‘產品編號’||v_pr.productid);
dbms_output.put_line(‘產品名稱’||v_pr.productname);
dbms_output.put_line(‘供應商編號’||v_pr.supplierid);
END LOOP;
END;
6.遊標變數
遊標包括顯示遊標和隱式遊標,它們都是靜態定義的,即在宣告中定義查詢。
遊標變數的定義包括兩個步驟:
(1) 定義遊標CURSOR型別的指標
TYPE type_name IS REF CURSOR [RETURN return_type];
type_name 是新引用型別的名字
而return_type表示該遊標變數返回的記錄型別。
(2) 宣告REF CURSOR型別的變數
遊標變數 type_name;
(3) 開啟遊標變數的語法格式如下所示:
OPEN 遊標變數名 FOR SELECT 語句;
遊標變數的不同宣告方式舉例
DECLARE
1、-- 用 %ROWTYPE型別定義遊標變數的返回值.
TYPE t_productsRef IS REF CURSOR
RETURN products%ROWTYPE;
2、 -- 定義一個新的記錄型別
TYPE t_prodRecord IS RECORD (
prodid products.productid%TYPE,
prodname products.productname%TYPE);
--定義遊標變數的返回值為記錄型別變數
TYPE t_prodRef IS REF CURSOR
RETURN t_prodRecord;
例6:使用遊標變數查詢出產品表中類別為1的產品的資訊,並輸出產品名稱、類別編號、單價。
DECLARE
TYPE prod_record IS RECORD
( pname products.productname%type,
cid products.categoryid%type,
uprice products.unitprice%type);
TYPE prod_cursor IS REF CURSOR RETURN prod_reord;
v_prodcur prod_cursor ;
v_prodrec prod_record;
BEGIN
OPEN v_prodcur FOR select productname,categoryid,unitprice from products where categoryid=1;
LOOP
FETCH v_prodcur INTO v_prodrec ;
EXIT WHEN v_prodcur%notfound;
dbms_output.put_line (‘產名’||v_prodrec.pname);
dbms_output.put_line(‘產品類別’||v_prodrec.cid);
dbms_output.put_line (‘單價’||v_prodrec.uprice);
End LOOP;
Close v_prodcur;
End;
使用同一遊標變數開啟多個查詢
例5:使用遊標變數查詢出產品表中類別為1的產品的資訊,然後查詢輸出產品單價小於20的產品資訊。
DECLARE
TYPE prod_cursor IS REF CURSOR;
v_cur prod_cursor;
v_rec products%rowtype;
BEGIN
OPEN v_cur FOR select * from products where categoryid=1;
LOOP
FETCH v_cur INTO v_rec;
EXIT WHEN v_cur%notfound;
dbms_output.put_line('產品名' || v_rec.productname);
dbms_output.put_line('產品類別' || v_rec.categoryid);
dbms_output.put_line('單價' || v_rec.unitprice);
End LOOP;
OPEN v_cur FOR select * from products where unitprice<20;
LOOP
FETCH v_cur INTO v_rec;
EXIT WHEN v_cur%notfound;
dbms_output.put_line('產品名' || v_rec.productname);
dbms_output.put_line('產品類別' || v_rec.categoryid);
dbms_output.put_line('單價' || v_rec.unitprice);
End LOOP;
Close v_cur;
End;