1. 程式人生 > >遊標、例外、儲存過程、儲存函式、java呼叫儲存過程、觸發器(Oracle之二)

遊標、例外、儲存過程、儲存函式、java呼叫儲存過程、觸發器(Oracle之二)

--遊標(游標) 一般用於多行資料

語法:cursor 遊標名稱 (引數名 引數型別 ..) is select語句

--操作遊標

open 遊標名; --開啟遊標

loop

  fetch 遊標名 into 記錄型變數; --取出一條記錄,放入記錄型變數中

  exit when 遊標名%notfound; --當遊標取空,退出

  (具體操作)

end loop;

close 遊標名; --關閉遊標

--1、用遊標方式輸出emp表中的員工編號和姓名

declare

  cursor empList is select * from emp;

  pemp emp%rowtype;

begin

  open empList;

  loop

    fetch empList into pemp;

    exit when empList%notfound;

    dbms_output.put_line(pemp.empno||'-'||pemp.ename);

  end loop;

  close empList;

end;

--2、寫一段PL/SQL程式,為部門號=10的員工漲工資

declare

  cursor addSal is select * from emp where deptno=10;

  pemp emp%rowtype;

begin

  open addSal;

  loop

    fetch addSal into pemp;

    exit when addSal%notfound;

    update emp set sal = sal +100 where empno = pemp.empno;

    commit;

  end loop;

  close addSal;

end;

--3、寫一段PL/SQL程式,某部門號的員工漲工資

declare 

  cursor addSal (dpn number) is select * from emp where deptno=dpn;

  pemp emp%rowtype;

begin

  open addSal (20); --此時指定實參

  loop

    fetch addSal into pemp;

    exit when addSal%notfound;

    update emp set sal = sal +1 where empno = pemp.empno;

    commit;

  end loop;

  close addSal;

end;

--exception 例外 (異常)

declare

begin 

[exception]

end;

--系統定義的異常

no_data_found --沒有找到資料

too_many_rows --select..into語句匹配多個行

zero_divide   --被零除

value_error   --算數或轉換錯誤

timeout_on_resource --等待資源超時

declare

  pnum number;

begin

  --pnum:=1/0;

  pnum:='數字型別賦值字串';

  exception

    when zero_divide then 

      dbms_output.put_line('被零除異常');

    when value_error then 

      dbms_output.put_line('算數或轉換錯誤');

    when others then 

      dbms_output.put_line('其他異常');

end;

--自定義的異常

--1、查詢部門編號是50 的員工,如果沒有員工,則提示'沒有找到員工'

declare

  cursor dept_emp is select * from emp where deptno = 50;

  pemp emp%rowtype;

  no_found_emp exception; --宣告異常

begin

  open dept_emp;

    fetch dept_emp into pemp;

    if dept_emp%notfound then 

      raise no_found_emp; --丟擲異常

    end if;

  close dept_emp;

  exception

    when no_found_emp then --捕獲異常

      dbms_output.put_line('沒有找到員工');

end;

--儲存過程:把pl/sql提前封裝(編譯)好,放在服務端,以便於再次呼叫

語法:

create [or replace] procedure 名稱[(引數名 in/out 引數型別)]

as|is

begin

  PLSQL程式

end[儲存過程名稱];

--1、給指定的員工漲100工資,並打印出漲前和漲後的工資

create procedure addSal(epn in  number) --建立儲存過程

as

  be_sal number;

  af_sal number;

begin

  select sal into be_sal from emp where empno=epn;

  update emp set sal =sal+100 where empno=epn;

  commit;

  select sal into af_sal from emp where empno=epn;

  dbms_output.put_line(be_sal||'-'||af_sal);

end;

--呼叫儲存過程

--第一種

call addSal(7369);

--第二種:在pl/sql呼叫

declare

begin

  addSal(7369);

end;

--2、使用儲存過程來查詢指定員工的年薪

create procedure yearSal(epn in number,total out number)

as 

  psal number;

  pcomm number;

begin

  select sal,comm into psal,pcomm from emp where empno=epn;

  total:=psal*12+nvl(pcomm,0);

end;

--呼叫儲存過程

declare

  total number;

begin

  yearSal(7369,total);

  dbms_output.put_line(total);

end;

--3、查詢指定[部門]的員工

create procedure empList (dpn in number,cur_emp out sys_refcursor) --遊標型變數

as

begin

  open cur_emp for select * from emp where deptno=dpn;--給遊標型變數放入多行結果集

end;

declare  --呼叫

  cur_emp sys_refcursor;

  pemp emp%rowtype;

begin

  empList(10,cur_emp); --呼叫儲存過程

  loop

    fetch cur_emp into pemp;

    exit when cur_emp%notfound;

    dbms_output.put_line(pemp.empno||'-'||pemp.ename);

  end loop;

  close cur_emp; --關閉遊標

end;

--儲存函式

語法:

create [or replace] function 函式名(Name in type,Name out type ..) return 資料型別

as|is

  結果變數 資料型別;

begin

  PLSQL程式;

  return (結果變數);

end[函式名];

--1、使用儲存函式來查詢指定員工的年薪

create or replace function f_getYearSal(epn in number) return number

as

  psal number;

  pcomm number;

begin

  select sal,comm into psal,pcomm from emp where empno=epn;

  return psal*12+nvl(pcomm,0);

end;

declare --呼叫儲存函式

  total number;

begin

  total:=f_getYearSal(7369);

  dbms_output.put_line(total);

end;

--函式和過程的區別

儲存函式有返回值,但是過程和函式都可以使用out型別的引數返回一個或者多個值

--用java呼叫儲存過程

  |-先用java查詢emp


  |-呼叫儲存過程(yearsal)


  |-呼叫(empList)


--觸發器

語法:

  create [or replace] trigger 觸發器名稱

  before|after

  insert|delete|update [of 列名]

  on 表名

  [for each row]

  declare 

  begin

  end;

--例如:

create table person(

       id number(10),

       name varchar2(20)

)

--插入員工後列印一句話'一個新員工插入成功'

create trigger addPerson

after

insert

on person

for each row

declare

begin

  dbms_output.put_line('一個新員工插入成功');

end;  

insert into person values(1,'張三'); --測試

--不能在指定星期幾增加新員工(此時是星期五)

--報錯

raise_application_error(-20001,'不能再今天插入新員工') -- -20001~20999

create trigger noAdd

before

insert

on person

declare

  week varchar2(20);

begin

  select to_char(sysdate,'day') into week from dual;

  if trim(week)='friday' then

    raise_application_error(-20001,'不能在星期五增加員工');

  end if;

end;

insert into person values(1,'張三'); --測試

--emp表中,判斷員工漲工資的工資值一定大於漲工資之前的工資

只有在for each row出現時可以使用 :old :new 

:old--偽記錄型變數 某個操作之前的資料

:new--偽記錄型變數 某個操作之後的資料

create or replace trigger addSal

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-1 where empno=7369;--測試

update emp set sal = sal+1 where empno=7369;--測試

--實現主鍵自增列

--建表

create table test_user(

       id number(6) primary key,

       name varchar2(20) not null

)

--建立序列

create sequence seq_user;

--建立觸發器

create trigger seq_pk

before

insert

on test_user

for each row

declare

begin

  select seq_user.nextval into :new.id from dual;

  --將自增主鍵 賦值給即將插入資料的主鍵

end;

insert into test_user(name) values('李四');

待續……