Oracle之異常/存儲過程/函數/觸發器

1.異常
1.預約義異常:oracle定義了上千個異常,但只有21個最多見的異常,這些異常都規定好了名字,這些有名字的異常叫預約義異常。
語法:
exception
when 異常名 then
...
when 異常名 then
...
when others then
....
sqlcode:返回當前遇到 的oracle錯誤號
sqlerrm:返回當前遇到的oracle錯誤號對應的錯誤信息
no_data_found:沒有返回行數據
zero_divide:除數爲0
too_many_rows:返回了多行數據
access_into_null:爲一個未初始化的對象的屬性賦值
示例:
declare
 v_ename varchar(20);
begin
 select ename into v_ename from emp where empno=8790;
 dbms_output.put_line('........');
exception
 when no_data_found then
 dbms_output.put_line('沒查到數據');
 dbms_output.put_line(sqlcode||'---'||sqlerrm);
 when others then
 dbms_output.put_line('未知錯誤');
end;
2.非預約義異常:只有錯誤編碼號和錯誤描述,但該異常沒名字。
exception
 when others then
 if sqlcode=-1843 then
 ...
 end if;
使用步驟:
 1.定義異常:異常名 exception;
 2.將定義好的異常名與錯誤號關聯起來:pragma exception_init(異常名,錯誤碼);

示例:declare
 my_exc exception;
 pragma exception_init(my_exc,-2292);
begin
 delete class;
exception
 when my_exc then
  dbms_output.put_line('學生表引用了class表');
 dbms_output.put_line(sqlcode||'--'||sqlerrm);
end;
3.自定義異常不是oracle的標準錯誤,是業務邏輯錯誤。
使用步驟:
 1.定義異常:異常名 exception;
 2.在適當時候拋出異常:raise 異常名;
 3.在exception中對拋出的異常進行處理

示例:修改指定員式的工資
declare
 no_result exception;
 v_empno emp.empno%type:=&no;
begin
 update emp set sal=sal+500 where empno=v_empno;
 if sql%notfound then
  raise no_result;
 end if;
exception
 when no_result then
  dbms_output.put_line('沒有更新');
  dbms_output.put_line(sqlcode||'--'||sqlerrm);
end;
自定義異常的另外一種用法:
 raise_application_error(錯誤號,錯誤信息);容許使用的錯誤號範圍:(-20000)---(-20999)
declare
 v_empno emp.empno%type:=&no;
begin
 update emp set sal=sal+500 where empno=v_empno;
 if sql%notfound then
  raise_application_error(-20000,'沒有成功更新數據');
 end if;
exception
 when others then
  if sqlcode=-20000 then
  dbms_output.put_line('xxxxx');
 end if;
end;
2.存儲過程(重點)
概念:是大型數據庫系統中,一組爲了完成特定功能的sql語句集,將其存儲在數據庫中,通過第一次編譯後可屢次調用。
怎麼使用?用戶經過指定存儲過程的名字並給出參數()來執行。
1.最簡單的存儲過程:

create or replace procedure p3 is--or replace可選,表示若是p3存在就替換java

建立存儲過程:sql

 begin
  insert into emp (empno,ename)values(007,'007a'),
 end;
執行存儲過程:
 exec p3;或call p3();
查詢存儲過程的錯誤:
 show error;
建立存儲過程語法:

create [or replace] procedure數據庫

過程名 (arg1 [in|out|in out] datatype,...) is|asoracle

變量的定義...app

num number(3);
...
begin
....
[exception]
end;
示例1:查詢指定工號的姓名
create or replace procedure p3(num number) is
 name varchar(8);
begin
 num:=100;
 select ename into name from emp where empno=num;
 dbms_output.put_line('員工的工號:'||name);
end;
執行:exec p3(111);或call p3(111);
注意:過程的參數若是沒有in,out,in out修飾,默認是in,in至關於java中的final修飾
create or replace procedure p3(num in number,name in varchar2,tmp out number) is
begin
 tmp:=100;
 insert into emp(empno,ename)values(num,name);
 dbms_output.put_line('出參值:'||tmp);
end;
若是有出參,要放在匿名塊或其餘存儲過程當中使用。
declare
 out_para number(3);
begin
 p3(9,'a9',out_para);
 dbms_output.put_line('被改變後的值:'||out_para);
end;
三種參數的特色:
in參數:由調用者傳入,而且只能被過程讀取,不能被修改;
out參數:由過程傳出給調用者,在執行過程當中該參數將被過程修改
in out:同時具備in和out參數的特色
3.函數:
建立函數語法:create [or replace] function 函數名(arg1 {in|out|in out}datetype,....)
return datatype; //函數的返回值類型(必須聲明)
is|as
變量的定義...;
bein
...
return exception;
exception
...
end;
示例:根據員工工號,查詢出該員工一年的總收入(包括獎金)
create or replace function get_incom(spno in number)return number is
 v_sumsal number(7,2);
 e_null exception;
 e_error exception;
begin
 if spno is null then
  raise e_null;
 elsif spno<0 then
  raise e_error;
 else
  select nvl2(comm,sal+comm,sal)*12 into v_sumsal from emp where empno=spno;
  return v_sumsal;
 end if;
exception
 when e_null then
  dbms_output.put_line('員工的工號不能爲空!');
  return 0;
 when e_error then
  dbms_output.put_line('員工的工號不能爲負數!');
  return -1;
 when no_data_found then
  dbms_output.put_line('員工的工號不存在!');
  return -2;
 when others then
  dbms_output.put_line(sqlcode||'----'||sqlerrm);
  return -3;
end;

declare
 v_sumsal number(7,2);
begin
 v_sumsal:=get_incom(7369);
 dbms_output.put_line('總收入:'||v_sumsal);
end;
函數與存儲過程區別:
1.過程沒有返回值,並且不能經過sql語句直接適用,只能經過exec或call或在塊中使用。
2.函數必須有返回值,可做爲sql或塊的表達式的一部分使用,函數的返回值類型在建立函數時使用。

4.觸發器(trigger):在作A(insert,update,delete)這件事時,會自動引發B事件(觸發器中定義的事件)的發生。(重點)
觸發的對象:table,view,database;
觸發的頻率:行級觸發或語句級觸發(對象觸發)
觸發的時間:在A事件以前觸發仍是在以後觸發

1.建立觸發器語法:
create[or replace] trigger 觸發器名 {before|after}
{insert|upadte|delete[ of col1[,col2...]]} on 表名
[for each row]
begin
...
end;
2.條件謂謂詞:inserting,updating,deleting
3.修飾符:new,old;(使用 :new|old.字段名)

示例:
create or replace trigger t1 after
 insert on emp
begin
 dbms_output.put_line('修改了emp表');
end;
練習1:當對emp修改(insert,update,delete)後,都會在dept表中增長一條記錄,只增長deptno,dname要用序列插入deptno
create or replace trigger t1 after
 insert or update or delete on emp
 for each row
begin
 if inserting then
  dbms_output.put_line('insert 了emp表');
 elsif updating then
  dbms_output.put_line('update 了emp表');
 else
  dbms_output.put_line('delete 了emp表');
 end if;
 insert into dept (deptno,dname)values(s2.nextval,'a'||s2.currval);
end;
示例:
create or replace trigger t1 before
 insert on emp
 for each row
begin
 if inserting then
  dbms_output.put_line('new value:'||:new.ename||'--工號:'||:new.empno||'--舊值:'||:old.ename);
 end if;
 end;
練習2:顯示增刪改的新舊值。
建立一個觸發器,當你刪除員工表中的數據時,要求把刪除的數據寫入到另外一張表中(emp_log)create table emp_log as select * from emp where 1=2;
create or replace trigger t1 before
 delete on emp
 for each row
begin
 insert into emp_log (empno,ename)values(:old.empno,:old.ename);
end;
練習3:建立觸發器,限制對dept表進行dml操做,具體以下:
只可在09:00~12:00修改表,並且還必須是週一到週五的工做日
create or replace trigger t1 before
insert or update or delete on dept
begin
 if to_char(sysdate,'day') in('星期六','星期日') or
  to_char(sysdate,'hh24') not between '09' and '12' then
  raise_application_error(-20001,'不能夠在不正確的時間修改數據');
 end if;
end;
練習4:修改emp表的員工工資,並輸出修改前和修改後的工資,同時要確保新工資不能比舊工資低。
create or replace trigger t1 before update of sal on emp
 for each row
begin
 if :old.sal>:new.sal then
  raise_application_error(-20003,'工資 不能比以前低');
 end if;
end;
4.系統觸發器
create trigger 名字 { before|after} 系統事件 on database
begin
...
end;
logon after:用戶鏈接事件
logoff before:用戶退出事件

create table user_log(user_name varchar(20),address varchar2(20),log_date date,logoff_date date);
create or replace trigger t1 after logon on database
begin
insert into user_log(user_name,address,log_date)values(ora_login_user,ora_client_ip_address,systimestamp);
end;
5.包:主要用來管理存儲過程,或函數等
建立包的語法:
1.包說明
 create [or replace] package 包名 is|as
 <函數或存儲過程,變量,遊標,異常,數據類型的聲明>
 end;
2.包體
 create[or replace] package body 包名 is
 <函數或存儲過程的定義>
 end;
練習:編寫一個包,該包中有一個過程能夠接收用戶名和新的sal,未來用戶可經過該用戶名更新工資,有一個函數,該函數可接收一個name,未來要經過name獲得該員工的年薪。
create or replace package pack1 is
--聲明一個過程
procedure pro1(en varchar2,newsal number);
function f1(en varchar2) return number;
end;

create or replace package body pack1 is
procedure pro1(en varchar2,newsal number) is
begin
 update emp set sal=newsal where ename=en;
end;

function f1(en varchar2)return number is
sumsal number;
begin
 --select nvl2(comm,sal+comm,sal)
 select (sal+nvl(comm,0))*12 into sumsal from emp where ename=en;
 return sumsal;
 end;
end;

declare
 v number;
begin
 v:=pack1.f1('SMITH');
 dbms_output.put_line(v);
end;
相關文章
相關標籤/搜索