/*游標是SQL的一個內存工作區(qū),有系統(tǒng)或用戶以變量的形式定義。游標的作用就是用于臨時存儲從數(shù)據(jù)庫中提取的數(shù)據(jù)塊。游標有兩種類型:顯示游標和隱式游標。一次從數(shù)據(jù)庫中提取一行數(shù)據(jù),對于這種形式的查詢和DML操作,系統(tǒng)都會使用一個隱式游標,如果要提取多行數(shù)據(jù),就要有程序員定義一個顯示游標,并通過與游標有關的語句進行處理。顯示游標對應一個返回結果為多行多列的SELECT語句。游標一旦打開,數(shù)據(jù)就從數(shù)據(jù)庫中傳送到游標變量中,然后應用程序再從游標中分解出需要的數(shù)據(jù),并進行處理。*//**隱式游標DML操作和單行SELECT語句使用隱式游標INSERT, UPDATE, DELETE, SELECT...INTO...當系統(tǒng)使用一個隱式游標時,可以通過隱式游標的屬性來了解操作的狀態(tài)和結果,進而控制程序的流程。隱式游標可以使用名字SQL來訪問,但要注意,通過SQL游標名總是只能訪問前一個DML操作或單行SELECT操作的游標屬性。所以通常在剛剛執(zhí)行完操作之后哦,立即使用SQL游標名來訪問屬性。游標的屬性有以下四種:隱式游標的屬性 返回值類型 意 義SQL%ROWCOUNT 整型 代表DML 語句成功執(zhí)行的數(shù)據(jù)行數(shù)SQL%FOUND 布爾型 值為TRUE 代表插入、刪除、更新或單行查詢操作成功SQL%NOTFOUND 布爾型 與SQL%FOUND 屬性返回值相反SQL%ISOPEN 布爾型 DML 執(zhí)行過程中為真,結束后為假*/--使用隱式游標的屬性,判斷對雇員工資的修改是否成功declarebegin update scott.emp emp set emp.sal = sal+100 where empno=7788; if SQL%FOUND then dbms_output.put_line('OK'); commit; else dbms_output.put_line('fail'); end if;end; --使用隱式游標的屬性,判斷修改員工的行數(shù)declarebegin update scott.emp emp set emp.sal = sal+1; dbms_output.put_line(SQL%ROWCOUNT); end; --輸出結果:20/**顯示游標顯示游標的使用分為以下4個步驟1. 聲明游標 在DECLARE部分按以下格式聲明游標: CURSOR 游標名[(參數(shù)1 數(shù)據(jù)類型[,參數(shù)2 數(shù)據(jù)類型...])] IS SELECT語句: 參數(shù)是可選部分,所定義的參數(shù)可以出現(xiàn)在SELECT語句的WHERE子句中。如果定義了參數(shù),則必須在打開游標時傳遞相應的實際參數(shù) SELECT語句是對表或視圖的查詢語句,甚至也可以是聯(lián)合查詢,可以帶WHERE條件、ORDER BY或GROUP BY等子句,但不能使用INTO子句。在SELECT語句中可以使用在定義游標之前定義的變量2. 打開游標 在可執(zhí)行部分,按以下格式打開游標 OPEN 游標名[(實際參數(shù)1[,實際參數(shù)2...])] 打開游標時,SELECT語句的查詢結果就被傳遞到了游標工作區(qū)。3. 提取數(shù)據(jù) 在可執(zhí)行部分,按以下格式將游標工作區(qū)中的數(shù)據(jù)提取到變量中。提取操作必須在打開游標之后進行。 FETCH 游標名 INTO 變量名1,變量2...] 或 FETCH 游標名 INTO 記錄變量; 游標打開后有一個指針指向數(shù)據(jù)區(qū),F(xiàn)ETCH語句一次返回指針值得一行數(shù)據(jù),要返回多行重復執(zhí)行,可以使用循環(huán)語句來實現(xiàn)??刂蒲h(huán)可以通過判斷游標的屬性來進行。下面對這兩種格式進行說明: 1).變量名是用來從游標中提取數(shù)據(jù)的變量,需要事先定義。變量的個數(shù)和類型應該與SELECT語句中的字段變量的個數(shù)和類型一致 2).一次將一行數(shù)據(jù)提取到記錄變量中,需要使用%ROWTYPE事先定義記錄變量,這種形式使用起來比較方便,不必分別定義和使用 多個變量 定義記錄變量的方法如下: 變量名 表名|游標名%ROWTYPE; 其中的表必須存在,游標名也必須先定義 4. 關閉游標 CLOSE 游標名 顯示游標名打開后,必須顯示地關閉。游標一旦關閉,游標占用的資源就被釋放,游標變成無效,必須重新打開才能使用。*/ --用游標提取emp表中7788雇員的名稱和職務declare v_ename varchar(10); v_job varchar(10); cursor emp_cursor IS select emp.ename, emp.job from scott.emp emp; begin open emp_cursor; fetch emp_cursor into v_ename, v_job; DBMS_OUTPUT.PUT_LINE(v_ename||','||v_job); close emp_cursor; end; --執(zhí)行結果:SCOTT,ANALYST --用游標變量提取emp中7788雇員的名稱和職務 declare cursor emp_cursor is select emp.ename, emp.job from scott.emp emp where emp.empno=7788; emp_record emp_cursor%ROWTYPE; begin open emp_cursor; fetch emp_cursor into emp_record; DBMS_OUTPUT.PUT_LINE(emp_record.ename||','||emp_record.job); close emp_cursor; end; --執(zhí)行結果:SCOTT,ANALYST --顯示工資最高的前三名雇員的名稱和工資。DECLARE v_ename varchar(10); v_sal number(5); cursor emp_cursor is select emp.ename, emp.sal from scott.emp emp where sal>0 order by sal desc ; begin open emp_cursor; for i in 1..3 loop fetch emp_cursor into v_ename, v_sal; DBMS_OUTPUT.PUT_LINE(v_ename||','||v_sal); end loop; close emp_cursor; end; /*輸出結果KING,5000SCOTT,3100FORD,3000*//* 游標循環(huán) 1*/--顯示全部雇員的編號和名稱。DECLARE CURSOR emp_cursor is select empno, ename from scott.emp; begin for emp_record in emp_cursor loop DBMS_OUTPUT.PUT_LINE(emp_record.empno||emp_record.ename); end loop; end;/* 游標循環(huán) 2 省略游標的定義,游標的SELECT查詢語句在循環(huán)中直接出現(xiàn)*/declarebegin for re in(select emp.ename from scott.emp emp) loop DBMS_OUTPUT.PUT_LINE(re.ename); end loop;end;/*顯示游標屬性雖然可以使用前面的形式獲得游標數(shù)據(jù),但是在游標定義以后使用它的一些屬性結構控制是一種更為靈活的方法。顯示游標的屬性如表:游標的屬性 返回值類型 意 義%ROWCOUNT 整型 獲得FETCH 語句返回的數(shù)據(jù)行數(shù)%FOUND 布爾型 最近的FETCH 語句返回一行數(shù)據(jù)則為真,否則為假%NOTFOUND 布爾型 與%FOUND 屬性返回值相反%ISOPEN 布爾型 游標已經打開時值為真,否則為假可按照以下形式取得游標的屬性游標名%屬性要判斷游標emp_cursor是否處于打開狀態(tài),可以使用屬性emp_cursor%ISOPEN。如果游標已經打開,則返回值為"真",否則為"假"*/declarev_ename varchar2(10);cursor emp_cursor isselect emp.ename from scott.emp emp;begin open emp_cursor; if emp_cursor%ISOPEN then loop fetch emp_cursor into v_ename; exit when emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(to_char(emp_cursor%ROWCOUNT)||'-'||v_ename); end loop; else DBMS_OUTPUT.PUT_LINE('用戶信息:游標沒有打開!'); end if; close emp_cursor; end;--帶參數(shù)的游標 打開游標的時候的參數(shù)declarev_empno number(5);v_ename varchar2(10);cursor emp_cursor(p_deptno number, p_job varchar2) is select empno, ename from scott.emp emp where emp.deptno=p_deptno and emp.job=p_job; begin open emp_cursor(10, 'CLERK'); if emp_cursor%ISOPEN then loop fetch emp_cursor into v_empno, v_ename; dbms_output.put_line(v_empno||'-'|| v_ename); exit when emp_cursor%NOTFOUND; end loop; else DBMS_OUTPUT.PUT_LINE('用戶信息:游標沒有打開!'); end if; end; --帶參數(shù)的游標 通過變量向游標傳遞參數(shù),變量需要先于游標定義,并在游標打開之前賦值 declare v_empno number(5); v_ename varchar(10); v_depno number(5); v_job varchar2(10); cursor emp_cursor IS select emp.empno, emp.ename from scott.emp emp where emp.deptno=v_depno and emp.job=v_job; begin v_depno:=10; v_job:='CLERK'; open emp_cursor; loop fetch emp_cursor into v_empno, v_ename; exit when emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_empno||','||v_ename); end loop; end; --輸出結果:7934,MILLER/* 動態(tài)SELECT語句和動態(tài)游標的用法 對于查詢結果為一行的select語句,可以用動態(tài)生成查詢語句字符串的方法,在程序執(zhí)行階段臨時生成并執(zhí)行, execute immediate 查詢語句字符串 into 變量1、、*/declarestr varchar2(100);v_ename varchar2(10);begin str := 'select emp.ename from scott.emp emp where emp.empno=7788'; execute immediate str into v_ename; dbms_output.put_line(v_ename); end;/*定義游標類型的語句如下:TYPE 游標類型名 REF CURSOR聲明游標變量的語句如下:在可執(zhí)行部分可以如下形式打開一個動態(tài)游標open 游標變量名 for 查詢語句字符串;*/--按名字中包含的字母順序分組顯示雇員信息declaretype cur_type is ref cursor;cur cur_type;--聲明為一個未綁定的游標rec scott.emp%rowtype;str varchar2(550);letter char :='A';begin loop str:='select emp.ename from scott.emp where emp.ename like ''%'||letter||'%'''; open cur for str; dbms_output.put_line('包含字母'||letter||'的名字:'); loop fetch cur into rec.ename; exit when cur%notfound; dbms_output.put_line(rec.ename); end loop; exit when letter='Z'; letter:=chr(ascii(letter)+1); end loop; end; /* 異常處理 錯誤是在標準包中由系統(tǒng)預定義的標準錯誤,或是有用戶在程序的說明部分自定義的錯誤。 */ --查詢編號為1234的雇員名字 declare v_name varchar2(10); begin select emp.ename into v_name from scott.emp emp where emp.empno=1234; DBMS_OUTPUT.PUT_LINE('該雇員名字為:'|| v_name); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('無改用戶'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('其他錯誤'); end; --執(zhí)行結果:無改用戶 --由程序代碼顯示系統(tǒng)錯誤 DECLARE V_TEMP NUMBER(5):=1; BEGIN V_TEMP:=V_TEMP/0; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('發(fā)生系統(tǒng)錯誤!'); DBMS_OUTPUT.PUT_LINE('錯誤代碼:'|| SQLCODE( )); DBMS_OUTPUT.PUT_LINE('錯誤信息:' ||SQLERRM( ));END;/*錯 誤 名 稱 錯誤代碼 錯 誤 含 義CURSOR_ALREADY_OPEN ORA_06511 試圖打開已經打開的游標INVALID_CURSOR ORA_01001 試圖使用沒有打開的游標DUP_VAL_ON_INDEX ORA_00001 保存重復值到惟一索引約束的列中ZERO_DIVIDE ORA_01476 發(fā)生除數(shù)為零的除法錯誤INVALID_NUMBER ORA_01722 試圖對無效字符進行數(shù)值轉換ROWTYPE_MISMATCH ORA_06504 主變量和游標的類型不兼容VALUE_ERROR ORA_06502 轉換、截斷或算術運算發(fā)生錯誤TOO_MANY_ROWS ORA_01422 SELECT…INTO…語句返回多于一行的數(shù)據(jù)NO_DATA_FOUND ORA_01403 SELECT…INTO…語句沒有數(shù)據(jù)返回TIMEOUT_ON_RESOURCE ORA_00051 等待資源時發(fā)生超時錯誤TRANSACTION_BACKED_OUT ORA_00060 由于死鎖,提交失敗STORAGE_ERROR ORA_06500 發(fā)生內存錯誤PROGRAM_ERROR ORA_06501 發(fā)生PL/SQL 內部錯誤NOT_LOGGED_ON ORA_01012 試圖操作未連接的數(shù)據(jù)庫LOGIN_DENIED ORA_01017 在連接時提供了無效用戶名或口令www.*/--定義新的系統(tǒng)錯誤類型。DECLAREV_ENAME VARCHAR2(10);NULL_INSERT_ERROR EXCEPTION;PRAGMA EXCEPTION_INIT(NULL_INSERT_ERROR,-1400);BEGININSERT INTO EMP(EMPNO) VALUES(NULL);EXCEPTIONWHEN NULL_INSERT_ERROR THENDBMS_OUTPUT.PUT_LINE('無法插入NULL值!');WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE('發(fā)生其他系統(tǒng)錯誤!');END;--執(zhí)行結果為:無法插入NULL值!
新聞熱點
疑難解答
圖片精選