遊標的概念:
遊標是SQL的一個內存工做區,由系統或用戶以變量的形式定義。遊標的做用就是用於臨時存儲從數據庫中提取的數據塊。在某些狀況下,須要把數據從存放在磁盤的表中調到計算機內存中進行處理,最後將處理結果顯示出來或最終寫回數據庫。這樣數據處理的速度纔會提升,不然頻繁的磁盤數據交換會下降效率。
遊標有兩種類型:顯式遊標和隱式遊標。在前述程序中用到的SELECT...INTO...查詢語句,一次只能從數據庫中提取一行數據,對於這種形式的查詢和DML操做,系統都會使用一個隱式遊標。可是若是要提取多行數據,就要由程序員定義一個顯式遊標,並經過與遊標有關的語句進行處理。顯式遊標對應一個返回結果爲多行多列的SELECT語句。
遊標一旦打開,數據就從數據庫中傳送到遊標變量中,而後應用程序再從遊標變量中分解出須要的數據,並進行處理。
隱式遊標
如前所述,DML操做和單行SELECT語句會使用隱式遊標,它們是:
* 插入操做:INSERT。
* 更新操做:UPDATE。
* 刪除操做:DELETE。
* 單行查詢操做:SELECT ... INTO ...。
當系統使用一個隱式遊標時,能夠經過隱式遊標的屬性來了解操做的狀態和結果,進而控制程序的流程。隱式遊標可使用名字SQL來訪問,但要注意,經過SQL遊標名老是隻能訪問前一個DML操做或單行SELECT操做的遊標屬性。因此一般在剛剛執行完操做以後,當即使用SQL遊標名來訪mysql
動手敲o~~~程序員
/* 遊標:是用來操做查詢結果集,至關因而JDBC中的ResultSet 語法:cursor 遊標名[(參數名 參數類型)] is 查詢結果集 開發步驟: 1.聲明遊標 2.打開遊標 3.從遊標中取數據 fetch 遊標名 into 變量 遊標名%found :找到數據 遊標名%notfound :沒找到數據 4.關閉遊標 close 遊標名 系統引用遊標 1. 聲明遊標 : 遊標名 sys_refcursor 2. 打開遊標: open 遊標名 for 結果集 3. 從遊標中取數據 4. 關閉遊標 for循環遍歷遊標: 不須要聲明額外變量 不須要打開遊標 不須要關閉遊標 */ --輸出員工表中全部的員工姓名和工資(不帶參數遊標) /* 遊標:全部員工 聲明一個變量,用來記錄一行數據 %rowtype */ declare --遊標 cursor vrows is select * from emp; --聲明變量,記錄一行數據 vrow emp%rowtype; begin --1.打開遊標 open vrows; --2.從遊標提取數據 --循環取數據 loop fetch vrows into vrow ; exit when vrows%notfound; dbms_output.put_line('姓名:'||vrow.ename ||' 工資: ' || vrow.sal); end loop; --3.關閉遊標 close vrows; end; --輸出指定部門下的員工姓名和工資 帶參數 /* 遊標:指定部門全部的員工 聲明一個變量記錄一行數據 */ declare cursor vrows(dno number) is select * from emp where deptno = dno; --聲明變量 vrow emp%rowtype; begin --1.打開遊標,指定10號部門 open vrows(10); --2.循環遍歷,取數據 loop fetch vrows into vrow; exit when vrows%notfound; dbms_output.put_line('姓名:'||vrow.ename ||' 工資: ' || vrow.sal); end loop; close vrows; end; --系統引用遊標 --輸出員工表中全部的員工姓名和工資 declare --聲明系統引用遊標 vrows sys_refcursor; --聲明變量 vrow emp%rowtype; begin --1.打開遊標 open vrows for select * from emp; --2.循環獲得數據 loop fetch vrows into vrow; exit when vrows%notfound; dbms_output.put_line('姓名:'||vrow.ename ||' 工資: ' || vrow.sal); end loop; close vrows ; end; --使用for循環遍歷遊標 declare cursor vrows is select * from emp; begin for vrow in vrows loop dbms_output.put_line('姓名:'||vrow.ename ||' 工資: ' || vrow.sal || '工做:'|| vrow.job); end loop; end; --按照員工工做給全部員工漲工資,總裁漲1000,經理漲800,其餘人漲400 /* 遊標全部員工 聲明一個記錄一行數據 */ declare cursor vrows is select * from emp; vrow emp%rowtype; begin open vrows; --循環 loop --取數據 fetch vrows into vrow; --退出條件 exit when vrows%notfound ; --根據不一樣的職位,漲工資 總裁漲1000,經理漲800,其餘人漲400 if vrow.job = 'PRESIDENT' then update emp set sal = sal + 1000 where empno = vrow.empno; elsif vrow.job = 'MANAGER' then update emp set sal = sal + 800 where empno = vrow.empno; else update emp set sal = sal + 400 where empno = vrow.empno; end if; end loop; --關閉遊標 close vrows; --提交事務 commit; end; /* 例外:(意外)程序運行的過程發生異常,至關因而JAVA中的異常 declare --聲明變量 begin --業務邏輯 exception --處理異常 when 異常1 then ... when 異常2 then ... when others then ...處理其它異常 end; zero_divide : 除零異常 value_error : 類型轉換異常 too_many_rows : 查詢出多行記錄,可是賦值給了rowtype記錄一行數據變量 no_data_found : 沒有找到數據 自定義異常: 異常名 exception; raise 異常名 */ declare vi number; vrow emp%rowtype; begin --vi := 8/0; --vi := 'aaa'; --select * into vrow from emp; select * into vrow from emp where empno=1234567; exception when zero_divide then dbms_output.put_line('發生了除零異常'); when value_error then dbms_output.put_line('發生了類型轉換異常'); when too_many_rows then dbms_output.put_line(' 查詢出多行記錄,可是賦值給了rowtype記錄一行數據變量'); when no_data_found then dbms_output.put_line('沒有找到數據異常'); when others then dbms_output.put_line('發生了其它異常' || sqlerrm); end; --查詢指定編號的員工,若是沒有找到,則拋出自定義的異常 /* --錯誤的演示 1.聲明一個變量 %rowtype 2.查詢員工信息,保存起來 3.判斷員工信息是否爲空 4. 若是是 則拋出異常 */ declare -- 1.聲明一個變量 %rowtype vrow emp%rowtype; --2 .聲明一個自定義的異常 no_emp exception; begin --查詢員工信息,保存起來 select * into vrow from emp where empno = 8888; --拋出異常 if vrow.sal is null then raise no_emp; --拋出自定義的異常 end if; exception when no_emp then dbms_output.put_line('輸出了自定義的異常'); when others then dbms_output.put_line('輸出了其它異常'||sqlerrm); end; --查詢指定編號的員工,若是沒有找到,則拋出自定義的異常 /* 遊標來判斷 %found %notfound 聲明一個遊標 聲明一個變量,記錄數據 從遊標中取記錄 若是有,則無論它 若是沒有就拋出自定義的異常 */ declare --聲明遊標 cursor vrows is select * from emp where empno=8888; --聲明一個記錄型變量 vrow emp%rowtype; --聲明一個自定義異常 no_emp exception; begin --1.打開遊標 open vrows; --2.取數據 fetch vrows into vrow; --3.判斷遊標是否有數據 if vrows%notfound then raise no_emp; end if; close vrows; exception when no_emp then dbms_output.put_line('發生了自定義的異常'); end; /* 存儲過程: 其實是封裝在服務器上一段PLSQL代碼片段,已經編譯好了的代碼 1.客戶端取調用存儲過程,執行效率就會很是高效 語法: create [or replace] procedure 存儲過程的名稱(參數名 in|out 參數類型,參數名 in|out 參數類型) is | as --聲明部分 begin --業務邏輯 end; */ --給指定員工漲薪,並打印漲薪前和漲薪後的工資 /* 參數 : in 員工編號 參數 : in 漲多少 聲明一個變量 : 存儲漲工資前的工資 查詢出當前是多少 打印漲薪前的工資 更新工資 打印漲薪後的工資 */ create or replace procedure proc_updatesal(vempno in number,vnum in number) is --聲明變量.記錄當前工資 vsal number; begin --查詢當前的工資 select sal into vsal from emp where empno = vempno; --輸出漲薪前的工資 dbms_output.put_line('漲薪前:'||vsal); --更新工資 update emp set sal = vsal + vnum where empno = vempno; --輸出漲薪後的工資 dbms_output.put_line('漲薪後:'||(vsal+vnum)); --提交 commit; end; select * from emp; --方式1 call proc_updatesal(7788,10); declare begin proc_updatesal(7788,-10); end; /* 存儲函數: 其實是一段封裝是Oracle服務器中的一段PLSQL代碼片段,它是已經編譯好了的代碼片斷 語法: create [or replace] function 存儲函數的名稱(參數名 in|out 參數類型,參數名 in|out 參數類型) return 參數類型 is | as begin end; 存儲過程和函數的區別: 1.它們本質上沒有區別 2.函數存在的意義是給過程調用 存儲過程裏面調用存儲函數 3.函數能夠在sql語句裏面直接調用 4.存儲過程能實現的,存儲函數也能實現,存儲函數能實現的,過程也能實現 默認是 in */ --查詢指定員工的年薪 /* 參數 : 員工的編號 返回 : 年薪 */ create or replace function func_getsal(vempno number) return number is --聲明變量,保存年薪 vtotalsal number; begin select sal*12+nvl(comm,0) into vtotalsal from emp where empno = vempno; return vtotalsal; end; --調用存儲函數 declare vsal number; begin vsal := func_getsal(7788); dbms_output.put_line(vsal); end; --查詢員工的姓名,和他的年薪 select ename,func_getsal(empno) from emp; --查詢指定員工的年薪--存儲過程來實現 --參數: 員工編號 --輸出: 年薪 create or replace procedure proce_getsal(vempno in number ,vtotalsal out number) is begin select sal*12+nvl(comm,0) into vtotalsal from emp where empno = vempno; end; --調用 declare vtotal number; begin proce_getsal(7788,vtotal); dbms_output.put_line('年薪:'||vtotal); end; /* JAVA調用存儲過程 JDBC的開發步驟: 1.導入驅動包 2.註冊驅動 3.獲取鏈接 4.獲取執行SQL的statement 5.封裝參數 6.執行SQL 7.獲取結果 8.釋放資源 */ /* 封裝一個存儲過程 : 輸出全部表中的記錄 輸出類型 : 遊標 */ create or replace procedure proc_getemps(vrows out sys_refcursor) is begin --1.打開遊標, 給遊標賦值 open vrows for select * from emp; end; /* 觸發器: 當用戶執行了 insert | update | delete 這些操做以後, 能夠觸發一系列其它的動做/業務邏輯 做用 : 在動做執行以前或者以後,觸發業務處理邏輯 插入數據,作一些校驗 語法: create [or replace] trigger 觸發器的名稱 before | after insert | update | delete on 表名 [for each row] declare begin end; 觸發器的分類: 語句級觸發器: 無論影響多少行, 都只會執行一次 行級觸發器: 影響多少行,就觸發多少次 :old 表明舊的記錄, 更新前的記錄 :new 表明的是新的記錄 */ --新員工入職以後,輸出一句話: 歡迎加入大少家庭 create or replace trigger tri_test1 after insert on emp declare begin dbms_output.put_line('歡迎加入大少家庭'); end; insert into emp(empno,ename) values(9527,'dashao'); --數據校驗, 星期六老闆不在, 不能辦理新員工入職 --在插入數據以前 --判斷當前日期是不是週六 --若是是週六,就不能插入 create or replace trigger tri_test2 before insert on emp declare --聲明變量 vday varchar2(10); begin --查詢當前 select trim(to_char(sysdate,'day')) into vday from dual; --判斷當前日期: if vday = 'saturday' then dbms_output.put_line('老闆不在,不能辦理入職'); --拋出系統異常 raise_application_error(-20001,'老闆不在,不能辦理入職'); end if; end; insert into emp(empno,ename) values(9528,'dashao2'); --更新全部的工資 輸出一句話 create or replace trigger tri_test3 after update on emp for each row declare begin dbms_output.put_line('更新了數據'); end; update emp set sal = sal+10; --判斷員工漲工資後的工資必定要大於漲工資前的工資 /* 200 --> 100 觸發器 : before 舊的工資 新的工資 若是舊的工資大於新的工資 , 拋出異常,不讓它執行成功 觸發器中不能提交事務,也不能回滾事務 */ create or replace trigger tri_updatesal before update on emp for each row declare begin if :old.sal > :new.sal then raise_application_error(-20002,'舊的工資不能大於新的工資'); end if; end; update emp set sal = sal + 10; select * from emp; update emp set sal = sal - 100; /* 模擬mysql中ID的自增屬性 auto_increment insert into person(null,'張三'); 觸發器: pid=1 insert pid=1 序列 : create sequence seq_person_pid; */ create table person( pid number primary key, pname varchar2(20) ); insert into person values(null,'張三'); create sequence seq_person_pid; --觸發器 create or replace trigger tri_add_person_pid before insert on person for each row declare begin dbms_output.put_line(:new.pname); --給新記錄 pid 賦值 select seq_person_pid.nextval into :new.pid from dual; end; insert into person values(null,'張三'); select * from person;