遊標、例外、儲存過程、儲存函式、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('李四');
待續……