Oracle數據庫遊標,序列,存儲過程,存儲函數,觸發器

遊標的概念: 
    遊標是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;
相關文章
相關標籤/搜索