Oracle cursor

 

 

--遊標分2種類型: --靜態遊標:結果集已經存在(靜態定義)的遊標,分爲隱式和顯示遊標post

  1. 隱式遊標:全部DML語句爲隱式遊標,經過隱式遊標屬性能夠獲取SQL語句信息
  2. 顯示遊標:用戶顯示聲明的遊標,即指定結果集,當查詢返回結果超過必定行時,就須要一個顯示遊標

--REF 遊標:動態關聯結果集的臨時對象this

  1. -強類型:帶return類型
  2. -弱類型: 不帶return類型

--隱式遊標 --在PL/SQL中編寫的每條SQL 語句實際上都是隱匿遊標。經過在DML操做後使用SQL%ROWCOUNT屬性,能夠 --知道語句所改變的行數(INSERT ,UPDATE,DELETE)返回理新行數,SELECT 返回查詢行數.
--顯示遊標 --語法:CURSOR 遊標名稱 ([參數列表,]) [RETURN 返回值類型] IS 子查詢(SELECT _statement) --第一步:聲明遊標: CURSOR 遊標名 IS SELECT 。。使用CURSOR定義 --第二步:打開遊標     使用OPEN     OPEN 遊標名 --第三步:提取遊標     使用FETCH  遊標 INTO 變量 --第四步:關閉遊標 CLOSE 遊標名 --顯式遊標屬性:   %FOUND     找到是否找到數據,有數據TRUE,沒有則FALSE   %ISOPEN    判斷遊標是否打開,打開則返回TRUE,沒有打開則返回FALSE   %NOTFOUND  返回FETCH ...INTO...是否有數據若是沒有返回TRUN,有則爲FALSE   %ROWCOUNT  返回執行FETCH 語句所返回的行數,初始爲0,每執行一行則%ROWCOUNT增長1 --隱式遊標屬性: SQL%FOUND     找到是否找到數據,有數據TRUE,沒有則FALSE   SQL%ISOPEN    判斷遊標是否打開,打開則返回TRUE,沒有打開則返回FALSE   SQL%NOTFOUND  返回FETCH ...INTO...是否有數據若是沒有返回TRUN,有則爲FALSE   SQL%ROWCOUNT  返回執行FETCH 語句所返回的行數,初始爲0,每執行一行則%ROWCOUNT增長1spa

隱式遊標:code

--驗證SQL%ROWCOUNT對象

DECLARE v_count NUMBER; BEGIN SELECT COUNT(*) INTO v_count FROM dept; --只返回一行結果 dbms_output.put_line('SQL%ROWCOUNT= '|| SQL%ROWCOUNT); END;

結果:SQL%ROWCOUNT= 1blog

--驗證SLQ%ROWCOUNT並返回行數input

DECLARE
BEGIN INSERT INTO dept(deptno,dname,loc)VALUES(90,'qqqq','北京'); dbms_output.put_line('SQL%ROWCOUNT= '|| SQL%ROWCOUNT); END;

結果:SQL%ROWCOUNT= 1it

--單行隱式遊標class

複製代碼
DECLARE v_empRow emp%ROWTYPE; BEGIN SELECT * INTO v_empRow FROM emp WHERE empno=7369; IF SQL%FOUND THEN --發現數據 dbms_output.put_line('員工姓名: '|| v_empRow.ename||'職位: '||v_empRow.job); END IF; END;
複製代碼

結果:員工姓名: SMITH職位: CLERK變量

--多行隱式遊標

複製代碼
DECLARE
BEGIN UPDATE EMP SET SAL = SAL * 1.2; IF SQL%FOUND THEN --發現數據 DBMS_OUTPUT.PUT_LINE('更新行數' || SQL%ROWCOUNT); ELSE DBMS_OUTPUT.PUT_LINE('更新行數' || SQL%ROWCOUNT); END IF; END;
複製代碼

結果:更新行數14

--顯示遊標 --定義遊標例1:

複製代碼
DECLARE
 CURSOR emp_cur IS SELECT empno,ename FROM emp; --定義遊標 v_id emp.empno%TYPE; --定義變量ID v_name emp.ename%TYPE; BEGIN OPEN emp_cur ; --打開遊標 FETCH emp_cur INTO v_id,v_name; ---提示取遊標  LOOP EXIT WHEN emp_cur%notFOUND; --判斷是否還有數據 dbms_output.put_line('員工編號'||v_id||',員工姓名:'||v_name); FETCH emp_cur INTO v_id,v_name; ---提示取遊標 END LOOP; CLOSE emp_cur; --關閉遊標 END;
複製代碼

結果:

複製代碼
員工編號7369,員工姓名:SMITH
員工編號7499,員工姓名:ALLEN
員工編號7521,員工姓名:WARD
員工編號7566,員工姓名:JONES
員工編號7654,員工姓名:MARTIN
員工編號7698,員工姓名:BLAKE
員工編號7782,員工姓名:CLARK
員工編號7788,員工姓名:SCOTT
員工編號7839,員工姓名:KING
員工編號7844,員工姓名:TURNER
員工編號7876,員工姓名:ADAMS
員工編號7900,員工姓名:JAMES
員工編號7902,員工姓名:FORD
員工編號7934,員工姓名:MILLER
複製代碼

--定義遊標例2:

複製代碼
DECLARE V_NAME VARCHAR2(50); --定義變量姓名 V_DNAME VARCHAR2(50); --定義變量部門名稱 CURSOR CUR_E IS --定義遊標 SELECT ENAME, DNAME FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO; BEGIN OPEN CUR_E; --打開遊標  LOOP --使用循環來讀取遊標 FETCH CUR_E INTO V_NAME, V_DNAME; --提取遊標 EXIT WHEN CUR_E%NOTFOUND; --判斷遊標是否還有內容 DBMS_OUTPUT.PUT_LINE(CUR_E%ROWCOUNT || ' 員工姓名:' || V_NAME || ' 部門名稱:' || V_DNAME); --輸出內容 END LOOP; CLOSE CUR_E; --關閉遊標 END;
複製代碼

結果:

複製代碼
程序結果:
1 員工姓名:SMITH 部門名稱:RESEARCH 2 員工姓名:ALLEN 部門名稱:SALES 3 員工姓名:WARD 部門名稱:SALES 4 員工姓名:JONES 部門名稱:RESEARCH 5 員工姓名:MARTIN 部門名稱:SALES 6 員工姓名:BLAKE 部門名稱:SALES 7 員工姓名:CLARK 部門名稱:ACCOUNTING 8 員工姓名:SCOTT 部門名稱:RESEARCH 9 員工姓名:KING 部門名稱:ACCOUNTING 10 員工姓名:TURNER 部門名稱:SALES 11 員工姓名:ADAMS 部門名稱:RESEARCH 12 員工姓名:JAMES 部門名稱:SALES 13 員工姓名:FORD 部門名稱:RESEARCH 14 員工姓名:MILLER 部門名稱:ACCOUNTING
複製代碼

另外一種指定變量類型:

複製代碼
DECLARE V_EMPNAME EMP.ENAME%TYPE; V_DNAME DEPT.DNAME%TYPE; CURSOR EMP_CUR IS SELECT E.ENAME, D.DNAME FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO; BEGIN OPEN EMP_CUR; LOOP FETCH EMP_CUR INTO V_EMPNAME, V_DNAME; EXIT WHEN EMP_CUR%NOTFOUND; DBMS_OUTPUT.PUT_LINE('員工姓名 :' || V_EMPNAME || ',部門名稱 :' || V_DNAME); END LOOP; CLOSE EMP_CUR; END;
複製代碼

結果同上

--定義遊標例3:

複製代碼
DECLARE
  CURSOR CUR_EMP IS SELECT * FROM EMP; V_EMPROW EMP%ROWTYPE; BEGIN IF CUR_EMP%ISOPEN THEN NULL; ELSE OPEN CUR_EMP; END IF; FETCH CUR_EMP INTO V_EMPROW; WHILE CUR_EMP%FOUND LOOP DBMS_OUTPUT.PUT_LINE('員工姓名: ' || V_EMPROW.ENAME || ',職位: ' || V_EMPROW.JOB || ' ,工資' || V_EMPROW.SAL); FETCH CUR_EMP INTO V_EMPROW; END LOOP; CLOSE CUR_EMP; END;
複製代碼

結果:

複製代碼
員工姓名: SMITH,職位: CLERK ,工資800
員工姓名: ALLEN,職位: SALESMAN ,工資1600
員工姓名: WARD,職位: SALESMAN ,工資1250
員工姓名: JONES,職位: MANAGER ,工資2975
員工姓名: MARTIN,職位: SALESMAN ,工資1250
員工姓名: BLAKE,職位: MANAGER ,工資2850
員工姓名: CLARK,職位: MANAGER ,工資2450
員工姓名: SCOTT,職位: ANALYST ,工資3000
員工姓名: KING,職位: PRESIDENT ,工資5000
員工姓名: TURNER,職位: SALESMAN ,工資1500
員工姓名: ADAMS,職位: CLERK ,工資1100
員工姓名: JAMES,職位: CLERK ,工資950
員工姓名: FORD,職位: ANALYST ,工資3000
員工姓名: MILLER,職位: CLERK ,工資1300
複製代碼

--使用FOR循環

複製代碼
DECLARE 
CURSOR cur_emp IS SELECT * FROM emp; BEGIN FOR emp_row IN cur_emp LOOP DBMS_OUTPUT.PUT_LINE('員工姓名: ' || emp_row.ENAME || ',職位: ' || emp_row.JOB || ' ,工資' || emp_row.SAL); END LOOP; END;
複製代碼

結果同上

--使用FOR循環操做遊標不只代碼簡單,並且能夠將遊標的狀態交給系統去完成,儘可能使用FOR循環爲主

--定義遊標例4:使用遊標UPDATE數據 --公司上市,決定給員工漲工資,入職年限超過1年加100,1000元封頂 --第一種 直接將計算的結果進行判斷

複製代碼
DECLARE V_ID EMP.EMPNO%TYPE; V_HIREDATE EMP.HIREDATE%TYPE; CURSOR EMP_CUR IS SELECT EMPNO, HIREDATE FROM EMP; BEGIN OPEN EMP_CUR; LOOP FETCH EMP_CUR INTO V_ID, V_HIREDATE; EXIT WHEN EMP_CUR%NOTFOUND; IF (TO_CHAR(SYSDATE, 'yyyy') - TO_CHAR(V_HIREDATE, 'yyyy')) * 100 < 1000 THEN UPDATE EMP SET SAL = SAL + (TO_CHAR(SYSDATE, 'yyyy') - TO_CHAR(V_HIREDATE, 'yyyy')) * 100 WHERE EMPNO = V_ID; DBMS_OUTPUT.PUT_LINE('工資增長成功'); COMMIT; ELSE UPDATE EMP SET SAL = SAL + 1000 WHERE EMPNO = V_ID; DBMS_OUTPUT.PUT_LINE('工資增長成功'); COMMIT; END IF; END LOOP; CLOSE EMP_CUR; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('數據異常'); ROLLBACK; END;
複製代碼

--第二種經過一個變量判斷

複製代碼
DECLARE V_ID EMP.EMPNO%TYPE; --定義員工編號ID V_HIREDATE EMP.HIREDATE%TYPE; --定義員工入職日期變量 V_SAL EMP.SAL%TYPE; --定義計算每一個員工要漲工資的總數變量 CURSOR CUR_EMP IS SELECT EMPNO, HIREDATE --定義遊標查詢員工ID和入職日期 FROM EMP; BEGIN IF CUR_EMP%ISOPEN THEN --判斷遊標是否打開 NULL; --打開了就什麼也不作 ELSE OPEN CUR_EMP; --沒有打開就打開遊標 END IF; LOOP FETCH CUR_EMP INTO V_ID, V_HIREDATE; EXIT WHEN CUR_EMP%NOTFOUND; V_SAL := (TO_CHAR(SYSDATE, 'yyyy') - TO_CHAR(V_HIREDATE, 'yyyy')) * 100; IF V_SAL < 1000 THEN --判斷是否小於1000 UPDATE EMP SET SAL = SAL + V_SAL WHERE EMPNO = V_ID; COMMIT; ELSE --大於1000 UPDATE EMP SET SAL = SAL + 1000 WHERE EMPNO = V_ID; COMMIT; END IF; END LOOP; CLOSE CUR_EMP; --關閉遊標 EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('數據異常'); ROLLBACK; --出現異常 就回滾 END;
複製代碼

--定義遊標例5 --在動態SELECT中使用遊標

複製代碼
DECLARE V_LOWSAL EMP.SAL%TYPE := &LOWSAL; V_HISAL EMP.SAL%TYPE := &HISSAL; CURSOR CUR_EMP IS SELECT * FROM EMP WHERE SAL BETWEEN V_LOWSAL AND V_HISAL; BEGIN FOR EMP_ROW IN CUR_EMP LOOP DBMS_OUTPUT.PUT_LINE('員工姓名: ' || EMP_ROW.ENAME || ',職位: ' || EMP_ROW.JOB || ' ,工資' || EMP_ROW.SAL); END LOOP; END;
複製代碼

--REF動態遊標 TYPE 類型名 IS REF CURSOR [RETURN]數據類型 遊標名 類型名       OPEN 遊標名 FOR 查詢語句 --強類型:帶RETURN

複製代碼
DECLARE TYPE REF_EMP IS REF CURSOR RETURN EMP%ROWTYPE; --定義一個REF動態遊標,並返回類型 CUR_EMP REF_EMP; --定義一個變量類型是上面的REF動態遊標也稱遊標變量 V_EMP EMP%ROWTYPE; --定義一個變量,類型和REF遊標返回類型相同,行類型 BEGIN OPEN CUR_EMP FOR SELECT * FROM EMP; --打開遊標,並關聯查詢語句  LOOP FETCH CUR_EMP INTO V_EMP; --提取遊標數據 EXIT WHEN CUR_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT||' 員工編號:' || V_EMP.EMPNO || ' 員工姓名:' || V_EMP.ENAME); END LOOP; CLOSE CUR_EMP; END;
複製代碼

--弱類型:不帶RETURN

複製代碼
DECLARE TYPE REF_EMP IS REF CURSOR; --定義一個REF動態遊標,並返回類型 CUR_EMP REF_EMP; --定義一個變量類型是上面的REF動態遊標也稱遊標變量 V_EMP EMP%ROWTYPE; --定義一個變量,類型和REF遊標返回類型相同,行類型 V_DEPT DEPT%ROWTYPE; --定義一個變量,類型和REF遊標返回類型相同,行類型 BEGIN --員工表 OPEN CUR_EMP FOR SELECT * FROM EMP; --打開遊標,並關聯查詢語句  LOOP FETCH CUR_EMP INTO V_EMP; --提取遊標數據 EXIT WHEN CUR_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT || ' 員工編號:' || V_EMP.EMPNO || ' 員工姓名:' || V_EMP.ENAME); END LOOP; CLOSE CUR_EMP; ------------下面是部門表 OPEN CUR_EMP FOR SELECT * FROM DEPT; --打開遊標,並關聯查詢語句  LOOP FETCH CUR_EMP INTO V_DEPT; --提取遊標數據 EXIT WHEN CUR_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE(CUR_EMP%ROWCOUNT || ' 部門編號:' || V_DEPT.DEPTNO || ' 部門名稱:' || V_DEPT.DNAME); END LOOP; CLOSE CUR_EMP; END;
複製代碼
在Oracle9i以後爲了方便用戶使用弱類型遊標變量,能夠使用  
SYS_REFCURSOR 來替代  TYPE REF_EMP IS REF CURSOR 上面的聲明能夠換爲: CUR_EMP SYS_REFCURSOR; --定義一個變量類型是上面的REF動態遊標也稱遊標變量 V_EMP EMP%ROWTYPE; --定義一個變量,類型和REF遊標返回類型相同,行類型 V_DEPT DEPT%ROWTYPE; --定義一個變量,類型和REF遊標返回類型相同,行類型

--根據用戶輸入,來輸出內容

複製代碼
DECLARE
  --TYPE REFC_T IS REF CURSOR;  REFC SYS_REFCURSOR; V_ID NUMBER; V_NAME VARCHAR2(50); V_INPUT VARCHAR(1) := UPPER(SUBSTR('&input', 1, 1)); BEGIN IF V_INPUT = 'E' THEN OPEN REFC FOR SELECT EMPNO, ENAME FROM EMP; DBMS_OUTPUT.PUT_LINE('=====員工表信息======'); ELSIF V_INPUT = 'D' THEN OPEN REFC FOR SELECT DEPTNO, DNAME FROM DEPT; DBMS_OUTPUT.PUT_LINE('=====部門表信息======'); ELSE DBMS_OUTPUT.PUT_LINE('=====員工表信息(E)或者部門表信息(D)======='); RETURN; END IF; FETCH REFC INTO V_ID, V_NAME; WHILE REFC%FOUND LOOP DBMS_OUTPUT.PUT_LINE(REFC%ROWCOUNT || '# ' || V_ID || ' ' || V_NAME); FETCH REFC INTO V_ID, V_NAME; END LOOP; CLOSE REFC; END;
複製代碼
相關文章
相關標籤/搜索