PL/SQL -- 隱式遊標 SQL FOUND
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
--===============================
-- PL/SQL -->隱式遊標(SQL%FOUND)
--===============================
在PL/SQL中,遊標的使用分為兩種,一種是顯示遊標,一種是隱式遊標,顯示遊標的使用需要事先使用declare來進行宣告,其過程包括
宣告遊標,開啟遊標,從遊標提取資料,關閉遊標。該方式多用於處理select語句返回的多行資料的情形。而隱式遊標則由則由系統自動定義
,當DML被使用時,Oracle為每一個不屬於顯示遊標的DML語句都建立一個隱式遊標,其宣告、開啟、關閉都是系統自動進行。多用於配合DML
返回單行資料的處理。
有關顯示遊標的使用,請參考:PL/SQL --> 遊標
一、隱式遊標的定義及其屬性
定義
隱式遊標則由則由系統自動定義,非顯示定義遊標的DML語句即被賦予隱式遊標屬性。其過程由oracle控制,完全自動化。隱式遊標
的名稱是SQL,不能對SQL遊標顯式地執行OPEN,FETCH,CLOSE語句。
屬性
通過SQL%總是隻能訪問前一個DML操作或單行SELECT操作的遊標屬性,用於判斷DML執行的狀態和結果,進而控制程式的流程
SQL%ISOPEN
遊標是否開啟。當執行select into ,insert update,delete時,Oracle會隱含地開啟遊標,且在該語句執行完畢或隱含地關閉
遊標,因為是隱式遊標,故SQL%ISOPEN總是false
SQL%FOUND
判斷SQL語句是否成功執行。當有作用行時則成功執行為true,否則為false。
SQL%NOTFOUND
判斷SQL語句是否成功執行。當有作用行時否其值為false,否則其值為true。
SQL%ROWCOUNT
在執行任何DML語句之前,SQL%ROWCOUNT的值都是NULL,對於SELECT INTO語句,如果執行成功,SQL%ROWCOUNT的值為,如果沒有
成功,SQL%ROWCOUNT的值為,同時產生一個異常NO_DATA_FOUND。
二、演示
1.SQL%FOUND的使用
DECLARE
v_empno emp.empno%TYPE:=&no;
BEGIN
UPDATE emp SET sal=sal+200 --根據給定的empno,更新一條記錄
WHERE empno=v_empno;
IF SQL%FOUND THEN --使用SQL遊標屬性SQL%FOUND作為判斷條件
COMMIT;
DBMS_OUTPUT.PUT_LINE('SQL code is executed successful');
ELSE
DBMS_OUTPUT.PUT_LINE('The Employee is not exist');
ROLLBACK;
END IF;
END;
Enter value for no: 7788
old 2: v_empno emp.empno%TYPE:=&no;
new 2: v_empno emp.empno%TYPE:=7788;
SQL code is executed successful
PL/SQL procedure successfully completed
2.SQL遊標的綜合應用(根據SQL遊標的不同屬性返回不同的結果)
DECLARE
v_dept emp.deptno%TYPE := &no;
BEGIN
IF SQL%ROWCOUNT >= 0 THEN --判斷更新前SQL%ROWCOUNT的屬性
DBMS_OUTPUT.PUT_LINE('SQL%ROWCOUNT value is ' || SQL%ROWCOUNT ||
'before updated');
ELSE
DBMS_OUTPUT.PUT_LINE('SQL%ROWCOUNT value is NULL before updated');
END IF;
UPDATE emp SET sal = sal + 200 WHERE deptno = v_dept;
IF SQL%FOUND THEN --判斷SQL%FOUND的屬性
DBMS_OUTPUT.PUT_LINE('SQL code is executed successful');
DBMS_OUTPUT.PUT_LINE('SQL%Found is TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE('No such department');
DBMS_OUTPUT.PUT_LINE('SQL%Found is FALSE');
END IF;
IF SQL%NOTFOUND THEN --判斷SQL%NOTFOUND的屬性
DBMS_OUTPUT.PUT_LINE('SQL%NotFound is TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE('SQL%NotFound is FALSE');
END IF;
IF SQL%ISOPEN THEN --判斷SQL%ISOPEN的屬性
DBMS_OUTPUT.PUT_LINE('SQL%ISOPEN is TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE('SQL%ISOPEN is FALSE');
END IF;
DBMS_OUTPUT.PUT_LINE('The rows updated is :' || SQL%ROWCOUNT ||
' rows by SQL Cursor'); --判斷SQL%ROWCOUNT的屬性
END;
Enter value for no: 10 --下面是成功更新後的結果
SQL%ROWCOUNT value is NULL before updated
SQL code is executed successful
SQL%Found is TRUE
SQL%NotFound is FALSE
SQL%ISOPEN is FALSE
The rows updated is :3 rows by SQL Cursor
Enter value for no: 80 --下面是未成功更新後的結果
SQL%ROWCOUNT value is NULL before updated
No such department
SQL%Found is FALSE
SQL%NotFound is TRUE
SQL%ISOPEN is FALSE
The rows updated is :0 rows by SQL Cursor
3.SELECT INTO時,隱式遊標的使用
SELECT INTO用於將單行結果集放置到變數之中。
SELECT INTO處理的結果包括兩種種情況
查詢結果返回單行,SELECT INTO被成功執行
查詢結果沒有返回行,PL/SQL將丟擲no_data_found異常
查詢結果返回多行,PL/SQL將丟擲too_many_rows 異常
對於上述兩種異常發生時,類似於普通異常處理,程式控制權轉移到異常處理部分(如沒有異常處理則程式中斷)。對於異常被激後發
,SQL遊標的四個屬性在此將不可使用,如下面的例子:
DECLARE
v_ename emp.ename%TYPE;
BEGIN
SELECT ename INTO v_ename FROM emp WHERE empno=&no;
IF SQL%ROWCOUNT=0 OR SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('The record '||&no||' is not exist!');
ELSE
DBMS_OUTPUT.PUT_LINE('The name for record '||&no||' is '||v_ename );
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data found for '||&no);
END;
Enter value for no:70
No data found for 70
Enter value for no:7788
The name for record 7788 is SCOTT
從上面的演示中可以看到,當select into沒有返回行時,IF SQL%ROWCOUNT=0 OR SQL%NOTFOUND THEN 語句並沒有被執行。
使用下面改進過的程式碼來執行,即可以將SQL遊標屬性判斷放置到EXCEPTION部分
DECLARE
v_ename emp.ename%TYPE;
BEGIN
SELECT ename INTO v_ename FROM emp WHERE empno=&no;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('The record '||&no||' is not exist!');
ELSE
DBMS_OUTPUT.PUT_LINE('The name for record '||&no||' is '||v_ename );
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('The record '||&no||' is not exist!');
DBMS_OUTPUT.PUT_LINE('No data found for '||&no);
ELSE
DBMS_OUTPUT.PUT_LINE('The name for record '||&no||' is '||v_ename );
END IF;
END;
Enter value for no:80
The record 80 is not exist!
No data found for 80
更多關於隱式遊標的探討,請參考:IMPLICIT CURSOR ATTRIBUTE SQL%NOTFOUND NOT WORKING
三、更多參考
有關SQL請參考
SQL 基礎--> ROLLUP與CUBE運算子實現資料彙總
SQL基礎-->層次化查詢(START BY ... CONNECT BY PRIOR)
有關PL/SQL請參考