?游標(Cursor)是Oracle數據庫中用于處理查詢結果集的重要機制,它允許開發者逐行處理SQL語句返回的數據。
目錄
一、游標基本概念
1. 游標定義
2. 游標分類?
二、靜態游標
(一)顯式游標
【一】不帶參數,普通的顯示游標
1. 顯式游標使用步驟
2. 語法
3. 顯式游標的四個屬性
4. 注意事項
5.?%notfound 和普通循環一起用
6.?%found 和while循環一起用
7.?基本示例
【二】帶參數的顯示游標
1. 語法結構
2. 示例代碼
3. 練習
(二)隱式游標
1.隱式游標的四個屬性
2. 示例代碼
二、動態游標
【動態游標注意事項】
【強類型游標和弱類型游標區別】
【動態游標類型定義】
(一)強類型游標
(二)弱類型游標(SYS_REFCURSOR)
(三)動態游標
三、游標變量與批量處理
1. 游標變量
2. 批量提取(BULK COLLECT)
3. 批量處理與FORALL
四、游標最佳實踐
五、高級游標技術
1. 可更新游標?
2. 游標子查詢
3. 游標表達式(12c+)
一、游標基本概念
1. 游標定義
游標是一個指向上下文區域的指針,用于處理SQL語句的執行結果。它提供了以下能力:
-
逐行訪問結果集
-
跟蹤當前處理的行
-
對結果集進行修改或刪除操作
2. 游標分類?
游標類型 | 描述 | 生命周期 | 控制方式 | |
---|---|---|---|---|
靜態 | 隱式游標 | Oracle自動為每條SQL語句創建?? ? | 單條SQL執行期間 | Oracle自動管理 |
顯式游標 | 開發者顯式定義 | 從OPEN到CLOSE | 開發者手動控制 | |
動態 | REF游標 | 動態游標,運行時確定 | 靈活控制 | 開發者控制 |
二、靜態游標
(一)顯式游標
顯示的游標:在declare的部分用is顯示了的游標
【一】不帶參數,普通的顯示游標
1. 顯式游標使用步驟
(1)聲明游標:定義游標及其關聯的SELECT語句
(2)打開游標:執行查詢,填充結果集
(3)提取數據:從結果集中獲取行數據
(4)關閉游標:釋放資源
2. 語法
-- 1. 聲明游標
CURSOR cursor_name [(parameters)][RETURN return_type]IS select_statement;-- 2. 打開游標
OPEN cursor_name [(parameters)];-- 3. 提取數據
FETCH cursor_name INTO variable_list;-- 4. 關閉游標
CLOSE cursor_name;-- 5. 舉例
declare
cursor cur_name is select語句;---聲明一個顯示游標
begin open cur_name;--打開游標fetch cur_name into 變量;--賦值變量,提取記錄dbms_output.put_line()---打印close cur_name;--關閉游標
end;
/
3. 顯式游標的四個屬性
屬性 | 返回值 | 描述 | 說明 |
cursor_name%FOUND | 布爾值 | 如果最近一次 FETCH返回行則為TRUE | 游標的指針是否有值(有)對 (沒有)?錯 |
cursor_name%NOTFOUND | 布爾值 | 如果最近一次 FETCH未返回行則為TRUE | 游標的指針是否沒值(有值)錯, (沒值)對,理論上可以返回空 在open之后fetch之前可以返回空 |
cursor_name%ROWCOUNT | 數值 | 到目前為止已提取的行數 | 游標的指針已經指了幾行,返回數值, 但是要賦給變量才能顯示 返回最近一次從游標讀取的數據 |
cursor_name%ISOPEN | 布爾值 | 如果游標已打開則為TRUE | 判斷是否打開游標(打開)對 (沒有)錯 |
4. 注意事項
首先聲明一個游標,使用之前先打開游標,提取記錄只能一行,可以多列
使用完游標要關閉游標,可以通過open打開游標繼續使用
5.?%notfound 和普通循環一起用
open→loop fetch→exit when %notfound→打印→end loop→close【舉例1】declarecursor cur_a is select * from emp;---聲明一個顯示游標v_emp emp%rowtype;---聲明變量v1 varchar2(20);---聲明變量
beginopen cur_a;--打開游標loop/*普通循環*/ fetch cur_a into v_emp;/*賦值變量,抓取記錄*/ exit when cur_a%notfound;/*和普通循環一起用*/ dbms_output.put_line(v_emp.ename); end loop;/*結束循環*/ close cur_a;/*關閉游標*/ end;
/-- LOOP循環語法
declare 部分;
beginloop 要執行的語句;exit when 退出的條件;end loop;
end;
注意事項:進入循環不需要條件
6.?%found 和while循環一起用
open→fetch→while %found loop→打印→fetch→end loop→close【舉例】
declarecursor cur_a is select * from emp;v_emp emp%rowtype;
beginopen cur_a;fetch cur_a into v_emp;while cur_a%found loopdbms_output.put_line(v_emp.ename);fetch cur_a into v_emp;end loop;close cur_a;
end;
7.?基本示例
DECLARE-- 1. 聲明游標CURSOR emp_cursor ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10;v_emp_id employees.employee_id%TYPE;v_name employees.last_name%TYPE;v_sal employees.salary%TYPE;
BEGIN-- 2. 打開游標OPEN emp_cursor;-- 3. 提取數據LOOPFETCH emp_cursor INTO v_emp_id, v_name, v_sal;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_name || ', ' || v_sal);END LOOP;-- 4. 關閉游標CLOSE emp_cursor;
END;
/1、輸出emp表工資前十名的員工姓名和薪資
declarecursor cur_1 isselect ename, salfrom (select ename, sal from emp order by sal desc)where rownum <= 10;v_n emp.ename%type;v_s emp.sal%type;
beginopen cur_1;loopfetch cur_1 into v_n, v_s;exit when cur_1%notfound;dbms_output.put_line('姓名:' || v_n || '薪資:' || v_s);end loop;close cur_1;
end;
/
-------------------
declarecursor cur_1 isselect ename, salfrom (select ename, sal from emp order by sal desc)where rownum <= 10;v_n emp.ename%type;v_s emp.sal%type;
beginopen cur_1;fetch cur_1 into v_n, v_s;while cur_1%found loopdbms_output.put_line('姓名:' || v_n || '薪資:' || v_s);fetch cur_1 into v_n, v_s;end loop;close cur_1;
end;
/
【二】帶參數的顯示游標
游標可以接受參數,使查詢更加靈活:
1. 語法結構
CURSOR cursor_name (parameter1 datatype, parameter2 datatype, ...)IS select_statement;declarecursor cur_name(變量 類型) is select語句;---聲明一個顯示游標
begin open cur_name(變量);--打開游標fetch cur_name into 變量;--賦值變量,提取記錄close cur_name;--關閉游標
end;
2. 示例代碼
DECLARE-- 帶參數的游標CURSOR emp_cursor (p_dept_id NUMBER, p_min_sal NUMBER) ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = p_dept_idAND salary >= p_min_sal;-- 記錄類型變量v_emp_record emp_cursor%ROWTYPE;
BEGIN-- 打開游標并傳入參數OPEN emp_cursor(10, 5000);LOOPFETCH emp_cursor INTO v_emp_record;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id || ': ' || v_emp_record.last_name || ', ' || v_emp_record.salary);END LOOP;CLOSE emp_cursor;
END;
/declarecursor cur_1(v1 number) is select sal from emp where empno = v1; --聲明一個帶參數的顯示游標v_s emp.sal%type; --負責接收的變量
beginopen cur_1(&a); ---(7788)即為(v1 number)fetch cur_1 into v_s;dbms_output.put_line(v_s);close cur_1;
end;
3. 練習
【1】輸出工作是MANAGER的姓名、工資、;工作是SALESMAN的姓名、傭金;
工作是CLERK的姓名、入職日期。
declarecursor cur_2(v1 varchar2) isselect * from emp where job = v1;v_emp emp%rowtype;
beginopen cur_2('MANAGER');---loopfetch cur_2into v_emp;exit when cur_2%notfound;dbms_output.put_line(v_emp.ename ||' '|| v_emp.sal);end loop;close cur_2;open cur_2('SALESMAN');loopfetch cur_2into v_emp;exit when cur_2%notfound;dbms_output.put_line(v_emp.ename ||' '|| v_emp.comm);end loop;close cur_2;open cur_2('CLERK');loopfetch cur_2into v_emp;exit when cur_2%notfound;dbms_output.put_line(v_emp.ename ||' '|| to_char(v_emp.hiredate,'yyyy-mm-dd'));end loop;close cur_2;
end;
/【2】輸出工作是MANAGER的姓名、工作、;工作是SALESMAN的姓名、傭金;
工作是CLERK的姓名、入職日期。
declarecursor cur_xx(v_1 emp.job%type) isselect * from emp where job = v_1;v_emp emp%rowtype;
beginopen cur_xx('MANAGER');loopfetch cur_xxinto v_emp;exit when cur_xx%notfound;dbms_output.put_line('員工姓名:'||v_emp.ename ||' '||'職位:'|| v_emp.job);end loop;close cur_xx;open cur_xx('SALESMAN');loopfetch cur_xxinto v_emp;exit when cur_xx%notfound;dbms_output.put_line('員工姓名:'||v_emp.ename ||' '||'工資:'|| v_emp.sal);end loop;close cur_xx;open cur_xx('CLERK');loopfetch cur_xxinto v_emp;exit when cur_xx%notfound;dbms_output.put_line('員工姓名:'||v_emp.ename ||' '||'入職日期:'||v_emp.hiredate);end loop;close cur_xx;
end;
/-----------------------------------------------------------------------------------------
輸出名字中包含%的人
select * from emp where ename like '%'||v1||'%' or ename like'%'||v_2||'%'【3】打印名字中包含A的人數,包含E的平均工資,包含o的總工資
declarecursor cur_3(v1 varchar2) is---先讓cur_3有了selecteselect count(sal), avg(sal), sum(sal)from empwhere ename like '%' || v1 || '%';----注意學習這種方法--聲明一個帶參數的顯示游標cur_3v_2 number;v_3 number;v_4 number;
----------------添加負責接收的變量
beginopen cur_3('A');loopfetch cur_3---又從cur_3里提取值賦值給變量v_2,v_3,v_4into v_2, v_3, v_4;exit when cur_3%notfound;dbms_output.put_line(v_2);end loop;close cur_3;---------------open cur_3('E');loopfetch cur_3into v_2, v_3, v_4;exit when cur_3%notfound;dbms_output.put_line(v_3);end loop;close cur_3;----------------open cur_3('O');loopfetch cur_3into v_2, v_3, v_4;exit when cur_3%notfound;dbms_output.put_line(v_4);end loop;close cur_3;----------------
end;
(二)隱式游標
主要應用于增加刪除更新數據,Oracle為每條DML語句自動創建隱式游標,當執行SQL語句的時候,這個游標是處理該語句的工作區域。在使用的時候要使用隱式游標的默認名稱SQL。?
1.隱式游標的四個屬性
屬性 | 返回 | 描述 | 說明 |
cursor_name%FOUND | 布爾值 | 如果DML操作影響至少一行返回TRUE | 游標的游標中是否有值,返回最近一次的結果,成功(對)否則(錯) |
cursor_name%NOTFOUND | 布爾值 | 如果DML操作未影響任何行返回TRUE | 游標的游標中是否有值,返回最近一次的結果,成功(錯) |
cursor_name%ROWCOUNT | 數值 | 返回DML操作影響的行數 | 返回最近一次從游標中讀取到的記錄--數值類型 |
cursor_name%ISOPEN | 布爾值 | 對隱式游標總是返回FALSE | 判斷是否打開游標。永遠返回錯 |
?補充:閃回不僅可以閃回刪除前的數據,也可以返回之前某一時間點的數據
2. 示例代碼
BEGIN-- 更新操作UPDATE employees SET salary = salary * 1.1 WHERE department_id = 10; -- 檢查隱式游標屬性IF SQL%FOUND THENDBMS_OUTPUT.PUT_LINE('更新了 ' || SQL%ROWCOUNT || ' 條記錄');END IF;-- 刪除操作DELETE FROM temp_employees WHERE employee_id = 9999;IF SQL%NOTFOUND THENDBMS_OUTPUT.PUT_LINE('未刪除任何記錄');END IF;
END;
----------------------------------------------------------------
----------------------------------------------------------------
/
begindelete from emp001 where deptno=10;--3--dbms_output.put_line('刪除了'||sql%rowcount||'行');delete from emp001 where deptno=20;--5if sql%found thendbms_output.put_line('刪除了'||sql%rowcount||'行') ;end if;end;
/
----------------------------------------------------------------
begin--dbms_output.put_line('刪除了'||sql%rowcount||'行');delete from emp001 where deptno in (10,20);--5if sql%found thendbms_output.put_line('刪除了'||sql%rowcount||'行') ;end if;
end;
/
----------------------------------------------------------------
----------------------------------------------------------------
declare
v_name csm_product.product_name%type;
begininsert into test_t values(1);if sql%found thendbms_output.put_line('收到影響的行數為:'||sql%rowcount);end if;rollback;
end;
----------------------------------------------------------------
----------------------------------------------------------------
declare
cursor v_cur is select * from test_t
beginif v_cur%isopen thendbms_output.put_line('游標已經打開');elsedbms_output.put_line('游標未打開');end if;open v_cur;if v_cur%isopen thendbms_output.put_line('游標已經打開');end if;close v_cur;insert into test_t valuse(1);if sql%found thendbms_output.put_line('執行成功,影響的行數:'||sql%rowcount)elsif sql%notfound thendbms_output.put_line('執行失敗');end if;rollback;
end;
二、動態游標
【動態游標注意事項】
1、使用動態游標必須聲明游標類型
2、只要列的格式相同,可以同時打開多表
【強類型游標和弱類型游標區別】
1、強類型游標有return,open時查詢得到的結果要和return后的表的數據類型、結構、順序一致。
2、沒有return,open時查詢的結果比較自由,fetch的時候into給的變量要和SQL查詢的類型結構數量一致。
【動態游標類型定義】
TYPE cursor_type IS REF CURSOR [RETURN return_type];
(一)強類型游標
DECLARETYPE emp_cursor_type IS REF CURSOR RETURN employees%ROWTYPE;emp_cursor emp_cursor_type;v_emp employees%ROWTYPE;
BEGINOPEN emp_cursor FOR SELECT * FROM employees WHERE department_id = 20;LOOPFETCH emp_cursor INTO v_emp;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp.employee_id || ': ' || v_emp.last_name);END LOOP;CLOSE emp_cursor;
END;
/declaretype cur_name_ref is ref cursor return emp%rowtype; --emp可以自定義,只是聲明了一個類型cur_1 cur_name_ref;v_emp emp%rowtype;
begin
--------------------------------------------------------------------open cur_1 for select * from emp;-------------同時打開多表---------fetch cur_1into v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;
--------------------------------------------------------------------open cur_1 for select * from emp001;---------同時打開多表----------fetch cur_1into v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;
end;
(二)弱類型游標(SYS_REFCURSOR)
DECLAREemp_cursor SYS_REFCURSOR;v_emp_id employees.employee_id%TYPE;v_emp_name employees.last_name%TYPE;
BEGIN-- 打開第一個查詢OPEN emp_cursor FOR SELECT employee_id, last_name FROM employees WHERE department_id = 10;DBMS_OUTPUT.PUT_LINE('部門10員工:');LOOPFETCH emp_cursor INTO v_emp_id, v_emp_name;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_emp_name);END LOOP;CLOSE emp_cursor;-- 重用游標執行不同查詢OPEN emp_cursor FOR SELECT department_id, department_name FROM departments;DBMS_OUTPUT.PUT_LINE('所有部門:');LOOPFETCH emp_cursor INTO v_emp_id, v_emp_name; -- 重用變量EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_emp_name);END LOOP;CLOSE emp_cursor;
END;
/declaretype cur_name_ref is ref cursor;---沒有return,和強類型的區別就在于此cur_name cur_name_ref;v_emp emp%rowtype;
beginopen cur_name for select * from emp;-------------同時打開多表---------------fetch cur_nameinto v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;---注意游標開一次,關一次,不然一直開著耗內存。open cur_name for select * from emp001;--------同時打開多表---------------fetch cur_nameinto v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;
end;【練習題】
1、輸出工作是MANAGER的姓名、工資;工作是SALESMAN的姓名、傭金;
工作是CLERK的姓名、入職日期。
declaretype cur_1_ref is ref cursor; ---沒有returncur_1 cur_1_ref;v1 varchar2(20);v2 number;v3 date;
beginopen cur_1 forselect ename, sal from emp where job = 'MANAGER';loopfetch cur_1into v1, v2;exit when cur_1%notfound;dbms_output.put_line(v1 || v2);end loop;open cur_1 forselect ename, sal from emp where job = 'SALESMAN';loopfetch cur_1into v1, v2;exit when cur_1%notfound;dbms_output.put_line(v1 || v2);end loop;open cur_1 forselect ename, hiredate from emp where job = 'CLERK';loopfetch cur_1into v1, v3;exit when cur_1%notfound;dbms_output.put_line(v1 || v3);end loop;
end;
/--用弱類型游標,打印emp名字中包含A的人數,dept部門編號的平均數
--salgrade 第三等級的hisal
declaretype cur_name_ref is ref cursor;cur_gam cur_name_ref;v_1 number;
beginopen cur_gam forselect count(ename) from emp where ename like '%A%';----單列單行不用循環fetch cur_gaminto v_1;dbms_output.put_line('名字包含A的人數:' || v_1);close cur_gam;open cur_gam forselect avg(deptno) from dept;----單列單行不用循環fetch cur_gaminto v_1;dbms_output.put_line('部門編號的平均數:' || v_1);close cur_gam;open cur_gam forselect hisal from salgrade where grade = 3;----單列單行不用循環fetch cur_gaminto v_1;dbms_output.put_line('第三等級的hisal:' || v_1);close cur_gam;
end;
--------如果多行多列,加入循環的寫法
declaretype cur_name_ref is ref cursor;cur_gam cur_name_ref;v_1 number;
beginopen cur_gam forselect count(ename) from emp where ename like '%A%';loopfetch cur_gaminto v_1;exit when cur_gam%notfound;dbms_output.put_line('名字包含A的人數:'||v_1);end loop;close cur_gam;
-----------------------open cur_gam forselect avg(deptno) from dept;loopfetch cur_gaminto v_1;exit when cur_gam%notfound;dbms_output.put_line('部門編號的平均數:'||v_1);end loop;close cur_gam;
-----------------------------open cur_gam forselect hisal from salgrade where grade=3;loopfetch cur_gaminto v_1;exit when cur_gam%notfound;dbms_output.put_line('第三等級的hisal:'||v_1);end loop;close cur_gam;
end;
(三)動態游標
【語法】
declarecur_name sys_refcursor;v1 number;v2 varchar2(20);
beginopen cur_name forselect empno, ename from emp where empno = 7788;fetch cur_nameinto v1, v2;dbms_output.put_line(v1 || v2);close cur_name;
--------------open cur_name forselect empno, ename from emp where deptno = 20;fetch cur_nameinto v1, v2;dbms_output.put_line(v1 || v2);close cur_name;
end;【練習題】
1、打印10部門的人員姓名和部門地址,打印20部門的工資和工資等級
declarecur_1 sys_refcursor;ve varchar2(20);vc varchar2(20);vs number;vg number;
beginopen cur_1 forselect e.ename,d.loc from emp e,dept d where e.deptno=d.deptno and d.deptno=10;loopfetch cur_1into ve, vc;exit when cur_1%notfound;dbms_output.put_line(ve ||' '|| vc);end loop;open cur_1 forselect e.sal, s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal and e.deptno=20;loopfetch cur_1into vs, vg;exit when cur_1%notfound;dbms_output.put_line(vs ||' '|| vg);end loop;close cur_1;
end;
/2、用動態游標里面的動態游標,打印emp名字中包含A的人數,dept部門編號的平均數,salgrade 第三等級的hisal
declarecur_2 sys_refcursor;v1 number;
beginopen cur_2 forselect count(ename) from emp where ename like '%A%';fetch cur_2into v1;dbms_output.put_line('名字包含A的人數:' || v1);close cur_2;
----------------------open cur_2 forselect avg(deptno) from dept;fetch cur_2into v1;dbms_output.put_line('部門編號的平均數:' || v1);close cur_2;
-----------------------open cur_2 forselect hisal from salgrade where grade = 3;fetch cur_2into v1;dbms_output.put_line('第三等級的hisal:' || v1);close cur_2;
end;
/
三、游標變量與批量處理
1. 游標變量
DECLARETYPE emp_cursor_type IS REF CURSOR;emp_cursor emp_cursor_type;PROCEDURE process_employees (p_cursor IN emp_cursor_type) ISv_emp employees%ROWTYPE;BEGINLOOPFETCH p_cursor INTO v_emp;EXIT WHEN p_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp.employee_id || ': ' || v_emp.last_name);END LOOP;END;
BEGINOPEN emp_cursor FOR SELECT * FROM employees WHERE department_id = 10;process_employees(emp_cursor);CLOSE emp_cursor;
END;
/
2. 批量提取(BULK COLLECT)
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10;-- 定義集合類型TYPE emp_id_array IS TABLE OF employees.employee_id%TYPE;TYPE name_array IS TABLE OF employees.last_name%TYPE;TYPE sal_array IS TABLE OF employees.salary%TYPE;v_ids emp_id_array;v_names name_array;v_sals sal_array;
BEGINOPEN emp_cursor;-- 批量提取數據FETCH emp_cursor BULK COLLECT INTO v_ids, v_names, v_sals;CLOSE emp_cursor;-- 處理批量數據FOR i IN 1..v_ids.COUNT LOOPDBMS_OUTPUT.PUT_LINE(v_ids(i) || ': ' || v_names(i) || ', ' || v_sals(i));END LOOP;
END;
/
3. 批量處理與FORALL
DECLARETYPE id_array IS TABLE OF employees.employee_id%TYPE;TYPE sal_array IS TABLE OF employees.salary%TYPE;v_ids id_array := id_array(101, 102, 103, 104, 105);v_new_sals sal_array;
BEGIN-- 批量查詢SELECT salary BULK COLLECT INTO v_new_salsFROM employeesWHERE employee_id IN (SELECT COLUMN_VALUE FROM TABLE(v_ids));-- 批量更新FORALL i IN 1..v_ids.COUNTUPDATE employeesSET salary = v_new_sals(i) * 1.1WHERE employee_id = v_ids(i);COMMIT;DBMS_OUTPUT.PUT_LINE('成功更新 ' || SQL%ROWCOUNT || ' 條記錄');
END;
/
四、游標最佳實踐
1.??及時關閉游標:避免資源泄漏
BEGINOPEN emp_cursor;-- 處理數據
EXCEPTIONWHEN OTHERS THENIF emp_cursor%ISOPEN THENCLOSE emp_cursor;END IF;RAISE;
END;
2. 使用游標FOR循環:簡化代碼,自動處理打開/關閉
3. 批量操作:對大結果集使用BULK COLLECT和FORALL
4. 參數化游標:提高代碼重用性
5. 限制返回行數:避免內存問題
FETCH emp_cursor BULK COLLECT INTO v_emps LIMIT 1000;
6. 使用合適的作用域:在包中定義常用游標
7. 性能監控:檢查游標SQL的執行計劃
五、高級游標技術
1. 可更新游標?
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10FOR UPDATE OF salary NOWAIT;v_raise_percent NUMBER := 0.1;
BEGINFOR emp_rec IN emp_cursor LOOPUPDATE employeesSET salary = salary * (1 + v_raise_percent)WHERE CURRENT OF emp_cursor;END LOOP;COMMIT;
END;
/
2. 游標子查詢
DECLARECURSOR dept_cursor ISSELECT d.department_id, d.department_name,CURSOR(SELECT employee_id, last_nameFROM employeesWHERE department_id = d.department_id) AS emp_cursorFROM departments dWHERE d.location_id = 1700;v_emp_cursor SYS_REFCURSOR;v_emp_id employees.employee_id%TYPE;v_emp_name employees.last_name%TYPE;
BEGINFOR dept_rec IN dept_cursor LOOPDBMS_OUTPUT.PUT_LINE('部門: ' || dept_rec.department_name);v_emp_cursor := dept_rec.emp_cursor;LOOPFETCH v_emp_cursor INTO v_emp_id, v_emp_name;EXIT WHEN v_emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(' ' || v_emp_id || ': ' || v_emp_name);END LOOP;CLOSE v_emp_cursor;END LOOP;
END;
/
3. 游標表達式(12c+)
DECLARECURSOR dept_cursor ISSELECT d.department_id, d.department_name,CURSOR(SELECT e.employee_id, e.last_nameFROM employees eWHERE e.department_id = d.department_id) AS emp_curFROM departments d;
BEGINFOR dept_rec IN dept_cursor LOOPDBMS_OUTPUT.PUT_LINE('部門: ' || dept_rec.department_name);FOR emp_rec IN dept_rec.emp_cur LOOPDBMS_OUTPUT.PUT_LINE(' 員工: ' || emp_rec.last_name);END LOOP;END LOOP;
END;
/
游標是Oracle PL/SQL中處理結果集的核心機制,掌握各種游標技術可以顯著提高數據庫應用程序的效率和靈活性。