帶參數的遊標
與存儲過程和函數相似,可以將參數傳遞給遊標並在查詢中使用。這對於處理在某種條件下打開遊標的情況非常有用。它的語法如下:
CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
定義參數的語法如下:
Parameter_name [IN] data_type[{:=|DEFAULT} value]
與存儲過程不同的是,遊標只能接受傳遞的值,而不能返回值。參數只定義數據類型,沒有大小。
另外可以給參數設定一個缺省值,當沒有參數值傳遞給遊標時,就使用缺省值。遊標中定義的參數只是一個佔位符,
在別處引用該參數不一定可靠。
在打開遊標時給參數賦值,語法如下:
OPEN cursor_name[value[,value]....];
參數值可以是文字或變量。
例:
DECLARE
CURSOR c_dept IS
SELECT * FROM dept ORDER BY deptno;
CURSOR c_emp(p_dept emp.deptno%type) IS
SELECT ename, sal FROM emp WHERE deptno = p_dept ORDER BY ename;
r_dept DEPT%ROWTYPE;
v_ename EMP.ENAME%TYPE;
v_salary EMP.SAL%TYPE;
v_tot_salary EMP.SAL%TYPE;
BEGIN
OPEN c_dept;
LOOP
FETCH c_dept
INTO r_dept;
EXIT WHEN c_dept%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Department:' || r_dept.deptno || '-' ||
r_dept.dname);
v_tot_salary := 0;
OPEN c_emp(r_dept.deptno);
LOOP
FETCH c_emp
INTO v_ename, v_salary;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name:' || v_ename || ' sal:' || v_salary);
v_tot_salary := v_tot_salary + v_salary;
END LOOP;
CLOSE c_emp;
DBMS_OUTPUT.PUT_LINE('Toltal Sal for dept:' || v_tot_salary);
END LOOP;
CLOSE c_dept;
END;
遊標FOR循環
在大多數時候我們在設計程序的時候都遵循下面的步驟:
1、打開遊標
2、開始循環
3、從遊標中取值
4、檢查那一行被返回
5、處理
6、關閉循環
7、關閉遊標
可以簡單的把這一類代碼稱爲遊標用於循環。但還有一種循環與這種類型不相同,這就是FOR循環,
用於FOR循環的遊標按照正常的聲明方式聲明,它的優點在於不需要顯式的打開、關閉、取數據,測試數據的存在、定義存放數據的變量等等
。遊標FOR 循環的語法如下:
FOR record_name IN
(corsor_name[(parameter[,parameter]...)]
| (query_difinition)
LOOP
statements
END LOOP;
下面我們用for循環重寫上面的例子:
DECLARE
CURSOR c_dept IS
SELECT deptno, dname FROM dept ORDER BY deptno;
CURSOR c_emp(p_dept emp.deptno%type) IS
SELECT ename, sal FROM emp WHERE deptno = p_dept ORDER BY ename;
v_tot_salary EMP.SAL%TYPE;
BEGIN
FOR r_dept IN c_dept LOOP
DBMS_OUTPUT.PUT_LINE('Department:' || r_dept.deptno || '-' ||
r_dept.dname);
v_tot_salary := 0;
FOR r_emp IN c_emp(r_dept.deptno) LOOP
DBMS_OUTPUT.PUT_LINE('Name:' || r_emp.ename || ' sal:' ||
r_emp.sal);
v_tot_salary := v_tot_salary + r_emp.sal;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Toltal Sal for dept:' || v_tot_salary);
END LOOP;
END;
在遊標FOR循環中使用查詢
在遊標FOR循環中可以定義查詢,由於沒有顯式聲明所以遊標沒有名字,記錄名通過遊標查詢來定義。
DECLARE
v_tot_salary EMP.SAL%TYPE;
BEGIN
FOR r_dept IN (SELECT deptno, dname FROM dept ORDER BY deptno) LOOP
DBMS_OUTPUT.PUT_LINE('Department:' || r_dept.deptno || '-' ||
r_dept.dname);
v_tot_salary := 0;
FOR r_emp IN (SELECT ename, sal
FROM emp
WHERE deptno = r_dept.deptno
ORDER BY ename) LOOP
DBMS_OUTPUT.PUT_LINE('Name:' || r_emp.ename || ' salary:' ||
r_emp.sal);
v_tot_salary := v_tot_salary + r_emp.sal;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:' || v_tot_salary);
END LOOP;
END;
遊標中的子查詢
語法如下:
CURSOR C1 IS SELECT * FROM emp
WHERE deptno NOT IN (SELECT deptno
FROM dept
WHERE dname!='ACCOUNTING');
可以看出與SQL中的子查詢沒有什麼區別。
遊標中的更新和刪除**************************************************************************POINT
在PL/SQL中依然可以使用UPDATE和DELETE語句更新或刪除數據行。顯式遊標只有在需要獲得多行數據的情況下使用。
PL/SQL提供了僅僅使用遊標就可以執行刪除或更新記錄的方法。
UPDATE或DELETE語句中的WHERE CURRENT OF子串專門處理要執行UPDATE或DELETE操作的表中取出的最近的數據。
要使用這個方法,在聲明遊標時必須使用FOR UPDATE子串,當對話使用FOR UPDATE子串打開一個遊標時,
所有返回集中的數據行都將處於行級(ROW-LEVEL)獨佔式鎖定,其他對象只能查詢這些數據行,
不能進行UPDATE、DELETE或SELECT...FOR UPDATE操作。
語法:
FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]
在多表查詢中,使用OF子句來鎖定特定的表,如果忽略了OF子句,那麼所有表中選擇的數據行都將被鎖定。
如果這些數據行已經被其他會話鎖定,那麼正常情況下ORACLE將等待,直到數據行解鎖。
在UPDATE和DELETE中使用WHERE CURRENT OF子串的語法如下:
WHERE{CURRENT OF cursor_name|search_condition}
例:
DECLARE
CURSOR c1 IS
SELECT empno, sal FROM test_emp WHERE comm IS NULL FOR UPDATE OF comm;
v_comm NUMBER(10, 2);
BEGIN
FOR r1 IN c1 LOOP
IF r1.sal < 500 THEN
v_comm := r1.sal * 0.25;
ELSIF r1.sal < 1000 THEN
v_comm := r1.sal * 0.20;
ELSIF r1.sal < 3000 THEN
v_comm := r1.sal * 0.15;
ELSE
v_comm := r1.sal * 0.12;
END IF;
UPDATE test_emp SET comm = v_comm WHERE CURRENT OF c1;
END LOOP;
END;