DECLARE
CURSOR c_stu IS SELECT studno, studname FROM studinfo WHERE classid = '20010505';
v_rec c_stu%ROWTYPE;
BEGIN
OPEN c_stu;
LOOP
FETCH c_stu INTO v_rec;
EXIT WHEN c_stu%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_rec.studno || ' ' || v_rec.studname);
END LOOP;
CLOSE c_stu;
END;
BEGIN
FOR r IN (SELECT studno, studname FROM studinfo WHERE classid = '20010505') LOOP
DBMS_OUTPUT.PUT_LINE(r.studno || ' ' || r.studname);
END LOOP;
END;
優點:代碼簡潔、自動處理屬性、無需聲明記錄變量。
| 屬性 | 顯式游標 | 隱式游標 (SQL%) |
|---|---|---|
| %FOUND | 最近 FETCH 是否返回行 | 最近 DML/SELECT INTO 是否影響行 |
| %NOTFOUND | %FOUND 邏輯反 | 同上 |
| %ROWCOUNT | **累計** FETCH 行數 (遞增) | **總影響行數** (最終值) |
| %ISOPEN | 游標是否打開 | 始終 FALSE (隱式即開即關) |
關鍵差異:顯式游標 %ROWCOUNT 在循環中遞增 (1,2,3...);隱式游標 SQL%ROWCOUNT 執行結束後直接是總行數。
CURSOR c_dept(p_loc VARCHAR2) IS
SELECT * FROM dept WHERE loc = p_loc;
BEGIN
FOR r IN c_dept('NEW YORK') LOOP ... END LOOP;
TYPE t_cur IS REF CURSOR;
PROCEDURE get_emp(p_deptno NUMBER, p_rc OUT t_cur) IS
BEGIN
OPEN p_rc FOR SELECT * FROM emp WHERE deptno = p_deptno;
END;
-- Java/.NET/PLSQL 均可消費
CREATE OR REPLACE PROCEDURE show_avg_desc IS
CURSOR c_rank IS
SELECT ROWNUM rn, studno, studname, classname, avg_score
FROM (
SELECT s.studno, studname, classname, ROUND(AVG(studscore),2) avg_score
FROM studinfo s, studscoreinfo ss, classinfo c
WHERE s.studno=ss.studno AND s.classid=c.classid
AND s.classid='20010505'
GROUP BY s.studno, studname, classname
ORDER BY AVG(studscore) DESC
);
BEGIN
FOR r IN c_rank LOOP
DBMS_OUTPUT.PUT_LINE('學號:'||r.studno||' 姓名:'||r.studname||
' 班級:'||r.classname||' 平均分:'||r.avg_score||' 名次:'||r.rn);
END LOOP;
END;
CREATE OR REPLACE PROCEDURE find_max_min_avg IS
CURSOR c_avg IS
SELECT s.studno, studname, classname, ROUND(AVG(studscore),2) avg_score
FROM studinfo s, studscoreinfo ss, classinfo c
WHERE s.studno=ss.studno AND s.classid=c.classid
AND s.classid='20010505'
GROUP BY s.studno, studname, classname
ORDER BY AVG(studscore) DESC;
v_cnt NUMBER := 0;
v_idx NUMBER := 0;
BEGIN
-- 第一遍計數
FOR r IN c_avg LOOP v_cnt := v_cnt + 1; END LOOP;
-- 第二遍取首尾
FOR r IN c_avg LOOP
v_idx := v_idx + 1;
IF v_idx = 1 OR v_idx = v_cnt THEN
DBMS_OUTPUT.PUT_LINE('學號:'||r.studno||' 姓名:'||r.studname||
' 班級:'||r.classname||' 平均分:'||r.avg_score);
END IF;
END LOOP;
END;
BULK COLLECT ... LIMIT 分批處理,減少上下文切換。REF CURSOR 適合異構調用,PL/SQL 內部優先強類型游標。