oracle存儲過程詳解--遊標 實現增、刪、改、查的(2)

帶參數的遊標 
  

    與存儲過程和函數相似,可以將參數傳遞給遊標並在查詢中使用。這對於處理在某種條件下打開遊標的情況非常有用。它的語法如下: 
  
  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;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章