1. 程式人生 > >儲存過程,遊標,觸發器

儲存過程,遊標,觸發器

-- 語法
/*
create [or replace] procedure 儲存過程名稱(引數名1 in|out 資料型別,引數名2 in|out 

資料型別,...)
as|is
-- 宣告變數
begin
-- 過程化語句
end;
*/
--- 根據員工編號得到員工的年薪
create or replace procedure getYearSal(eno in number , yearsal out number)
as

begin
select sal * 12 + nvl(comm,0) into yearsal from emp where empno = eno;
end;

-- 訪問儲存過程
declare
ys number;
begin
getYearSal(7788, ys);
dbms_output.put_line('年薪'||ys);
end;

--- 給某員工漲工資(列印漲前的工資和漲後的工資)
create or replace procedure updateSal(eno in number ,psal in number)
is
oldsal number;
newsal number;
begin
-- 列印漲前的工資
select sal into oldsal from emp where empno = eno;
dbms_output.put_line('漲前的工資:'||oldsal);
-- 漲工資
update emp set sal = sal + psal where empno = eno;
commit;
-- 列印漲後的工資
select sal into newsal from emp where empno = eno;
dbms_output.put_line('漲後的工資:'||newsal);

end;
-- 訪問只有輸入引數的儲存過程

call updateSal(7788,100);

---- 舉例:返回遊標的儲存過程
-- 得到某部門所有的員工資訊
create or replace procedure getEmps(dno in number ,emps out sys_refcursor)
as

begin
-- 給動態的遊標賦值
open emps for select * from emp where deptno = dno;
end;
-- 訪問帶有輸出引數為遊標的儲存過程
declare
emps sys_refcursor;
prow emp%rowtype;
begin
getEmps(20, emps);
loop
fetch emps into prow;
exit when emps%notfound;
dbms_output.put_line(prow.empno||','||prow.ename);

end loop;
close emps;
end;
遊標
## 四、遊標&例外
```
--- 遊標(集合): 用來處理返回多行記錄的問題
-- select into 語句只能解決返回一行記錄的問題
declare
pname emp.ename%type;
begin
select ename into pname from emp where deptno = 40;
dbms_output.put_line(pname);
end;

--- 宣告遊標
-- cursor 遊標名 is sql查詢語句;
-- 遍歷遊標的過程
-- 開啟遊標
-- 提取遊標中的一行內容: fetch 遊標名 into 變數名;
-- 迴圈語句, exit when 遊標名%notfound;
-- 關閉遊標
-- 舉例: 使用遊標列印20號部門的員工姓名和工作
declare
cursor cur is select ename ,job from emp where deptno = 20;
pname emp.ename%type;
pjob emp.job%type;
begin
-- 開啟遊標
open cur;
loop
fetch cur into pname,pjob;
-- 當遊標中沒有記錄時退出
exit when cur%notfound;
dbms_output.put_line(pname || ','|| pjob);
end loop;
-- 關閉遊標
close cur;
end;
-- 舉例
-- 使用遊標對20號部門的員工漲工資(100)
-- 找出20號部門的員工編號,更新工資
declare
cursor cur is select empno from emp where deptno = 20;
begin
-- for 迴圈:自動開啟,關閉遊標
for c in cur loop
update emp set sal = sal + 100 where empno = c.empno;
end loop;
end;

update emp set sal = sal +100 where deptno = 20;

### 八、觸發器
```
---- 觸發器(監聽器): 監聽表中的資料是否發生了改變
/*
create or replace trigger 觸發器名稱
before |after -- 改變之前執行觸發器還是之後執行
insert|update|delete
on 表 -- 修改的是哪一張表
[觸發器的級別:表級的觸發器,行級觸發器]
declare
begin
end;
*/
-- 舉例 : 新增一條記錄(列印添加了一條記錄)
create or replace trigger insertEmp
after
insert
on emp

declare
begin
dbms_output.put_line('添加了一條記錄');
end;

insert into emp(empno ,ename) values(1002,'zhangfei');

-- 不能給員工降薪
create or replace trigger notUpdateLowerSal
before
update
on emp
for each row -- 行級的觸發器:只要使用new,old 就必須使用行級觸發器
declare

begin
if :new.sal < :old.sal then
-- raise_application_error(p1,p2)
-- p1 : 錯誤的編號:- 20001 ~ -20999
-- p2 :錯誤的資訊
raise_application_error(-20001 , '不能給員工降薪');
end if;

end;

update emp set sal = sal - 1 where empno = 7788;

-- 使用觸發器來模擬mysql中自增的效果
create sequence tseq;


create or replace trigger autoIncrement
before
insert
on emp
for each row
declare

begin
select tseq.nextval into :new.empno from dual;
end;

insert into emp(empno,ename) values(100,'lisi');
select * from emp;