PL/SQL編程(四) 遊標、觸發器

/*
8、遊標
     顯示遊標:指的是遊標使用之前必須得先聲明定義,一般是對查詢語句的結果事進行定義遊標,然後通過打開遊標循環獲取結果集內的記錄,或者可以根據業務需求跳出循環結束遊標的獲取。循環完成後,可以通過關閉遊標,結果集就不能再獲取了。全部操作完全由開發者自己編寫完成,自己控制。
     隱式遊標:指的是PL/SQL自己管理的遊標,開發者不能自己控制操作,只能獲得它的屬性信息。
*/

/*
     顯示遊標  使用步驟
     1、聲明遊標
          declare cursor cursor_name(遊標名) is select_statement(查詢語句); 
     2、打開遊標 
          open cursor_name;
     3、讀取遊標中數據
          fetch cursor_name into record變量;
     4、關閉遊標 
          close cursor_name;
*/
--8.1.1   創建遊標給員工的薪水加1000
declare 
  cursor emp_addsal is select * from emp;--1 聲明遊標 emp_addsal
  emprow emp%rowtype;--定義emprow接收每行的數據      
begin
  open emp_addsal;--2 打開遊標
  loop-- 循環讀取遊標中的數據
    fetch emp_addsal into emprow;--3 讀取遊標中數據 到 emprow
          exit when emp_addsal%notfound;--如果數據讀取結束退出循環
          update emp set sal = (emprow.sal+1000) where empno = emprow.empno;--給對應員工工資加1000
  end loop;
  close emp_addsal;--關閉遊標
  commit;--提交數據
end;
/
select * from emp;--查詢員工工資

/*
     顯式遊標的屬性
     1、%NOTFOUND。表示遊標獲取數據的時候是否有數據提取出來,沒有數據返回TRUE,有數據返回false。經常用來判斷遊標是否全部循環完畢,如案例1%NOTFOUND爲true的時候,說明循環完畢,跳出LOOP循環。
     2、%FOUND。正好和%NOTFOUND相反,當遊標提取數據值時有值,返回TRUE,否則返回FALSE。
     3、%ISOPEN。用來判斷遊標是否打開。
     4、%ROWCOUNT。表示當前遊標FETCH INTO獲取了多少行的記錄值,用來做計數用的。
*/
--8.1.2   查看顯示遊標的屬性
declare 
  cursor emp_addsal is select * from emp;--1 聲明遊標 emp_addsal
  emprow emp%rowtype;--定義emprow接收每行的數據      
begin
  open emp_addsal;--2 打開遊標
  loop-- 循環讀取遊標中的數據
    fetch emp_addsal into emprow;--3 讀取遊標中數據 到 emprow
          exit when emp_addsal%notfound;--如果數據讀取結束退出循環
          if emp_addsal%found then--這裏if 判斷是多餘的 只是爲了顯示found的作用
             dbms_output.put_line(emp_addsal%rowcount);
          end if;
  end loop;
  close emp_addsal;--關閉遊標
end;
/

--8.2  隱式遊標   sql%found  上一條查詢語句包含返回數據
declare
  emprow emp%rowtype;
begin
  select * into emprow from emp where empno = 7369;
  if sql%found then
    dbms_output.put_line('找到編號7369的員工,薪水上漲10%');
    --update emp set sal = 1.1*sal where empno = 7369;--寫法1
    update emp set sal = 1.1*emprow.sal where empno = emprow.empno;--寫法2
    commit;--提交
  else
    dbms_output.put_line('沒有找到編號7369的員工');
  end if;
end;
/


/*
9、觸發器:Oracle觸發器是使用者對Oracle數據庫的對象做特定的操作時,觸發的一段PL/SQL程序代碼,叫做觸發器。觸發的事件包括對錶的DML操作,用戶的DDL操作以及數據庫事件等。

      觸發器分類:
       1、數據操作(DML)觸發器。
          create [ or replace] trigger tr_name(觸發器名) 
          before|after  
          delete| insert | update [of column1,column2...]
          [or delete |insert| update of colum1,colum2...]
          on table_name(表名) 
          [for each row]
          [follows tr_name1(其它觸發器名)]
          [when 條件] 
          declare
          --聲明部分
          begin
          --觸發器內容部分
          end;
       2、數據定義操作(DDL)觸發器。
          create [ or replace] trigger tr_name(觸發器名)
          before|after
          ddl_event|database_event
          on SCHEMA(數據庫對象)|DATABASE(數據庫)
          [follows tr_name1(其它觸發器名)]
          [when 條件] 
          declare
          --聲明部分
          begin
          --觸發器內容部分
          end;
       3、用戶和系統事件觸發器。
       4、INSTEAD OF 觸發器。
       5、複合觸發器。
*/   
--9.1.1 數據操作(DML)觸發器。 表級觸發器  不添加 for each row場景   
create or replace trigger tr_emp_update
before update on emp
begin
    if to_char(sysdate,'dd')=28 then
       raise_application_error(-20000,'每月28號不允許修改員工信息');--自定義異常錯誤號範圍 20000-20999
    end if;  
end;
/
update emp set sal = 10000;--測試觸發器
drop trigger tr_emp_update;--刪除觸發器


--9.1.2 數據操作(DML)觸發器。 表級觸發器  行級觸發器 對比  for each row
create or replace trigger tb_tr_emp_update
before update on emp
begin
    dbms_output.put_line('測試表級觸發器觸發次數');
end;
/
update emp set sal = 10000;--觸發器響應一次
rollback;--回滾操作
drop trigger tb_tr_emp_update;--刪除觸發器

create or replace trigger row_tr_emp_update
before update on emp
for each row--行級觸發器
begin
    dbms_output.put_line('測試行級觸發器觸發次數');
end;
/
update emp set sal = 10000;--觸發器響應多次
rollback;--回滾操作
drop trigger row_tr_emp_update;--刪除觸發器

--9.1.3 數據操作(DML)觸發器。insert  行級觸發器 new屬性
create or replace trigger tr_emp_insert
before insert on emp
for each row--new 和 old屬性只能出現在行級觸發器中  insert觸發器只有new屬性
begin
    if :new.empno=9999 then
       raise_application_error(-20000,'不允許使用9999員工號');--自定義異常錯誤號範圍 20000-20999
    end if;  
end;
/
insert into emp(empno) values(9999);--測試觸發器
drop trigger tr_emp_insert;--刪除觸發器

--9.1.4 數據操作(DML)觸發器。delete  行級觸發器 old 屬性
create or replace trigger tr_emp_delete
before delete on emp
for each row--new 和 old屬性只能出現在行級觸發器中  delete觸發器只有old屬性
begin
    if :old.empno=7369 then
       raise_application_error(-20000,'不允許刪除員工號7369的員工');--自定義異常錯誤號範圍 20000-20999
    end if;  
end;
/
delete from emp where empno = 7369;--測試觸發器
drop trigger tr_emp_delete;--刪除觸發器

--9.1.5 數據操作(DML)觸發器。update  行級觸發器 new屬性  old 屬性
create or replace trigger tr_emp_update
before update on emp
for each row--new 和 old屬性只能出現在行級觸發器中  delete觸發器只有old屬性
begin
    if :old.empno=7369 and :new.ename='zhangsan' then
       raise_application_error(-20000,'不允許修改員工號7369的員工姓名爲張三');--自定義異常錯誤號範圍 20000-20999
    end if;  
end;
/
update emp set ename = 'zhangsan' where empno = 7369;--測試觸發器
drop trigger tr_emp_update;--刪除觸發器

--9.1.6 數據操作(DML)觸發器。 before after關鍵字
create or replace trigger tr_emp_before
before delete on emp
begin
   dbms_output.put_line('before觸發器');
end;
/
create or replace trigger tr_emp_after
after delete on emp
begin
   dbms_output.put_line('after觸發器');
end;
/
delete from emp where empno = 9999;--測試觸發器
drop trigger tr_emp_before;--刪除觸發器
drop trigger tr_emp_after;--刪除觸發器

--9.1.7 數據操作(DML)觸發器。 follows 關鍵字
create or replace trigger tr_emp_before1
before delete on emp
begin
   dbms_output.put_line('before觸發器1');
end;
/
create or replace trigger tr_emp_before2
before delete on emp
follows tr_emp_before1
begin
   dbms_output.put_line('before觸發器2');
end;
/
create or replace trigger tr_emp_before3
before delete on emp
follows tr_emp_before2
begin
   dbms_output.put_line('before觸發器3');
end;
/
delete from emp where empno = 9999;--測試觸發器
drop trigger tr_emp_before1;--刪除觸發器
drop trigger tr_emp_before2;--刪除觸發器
drop trigger tr_emp_before3;--刪除觸發器

--9.1.7 數據操作(DML)觸發器。 when 關鍵字  必須同 行級觸發器一起使用
create or replace trigger tr_emp_before1
before delete on emp
for each row
when (to_char(sysdate,'dd')=28)
begin
   dbms_output.put_line('when關鍵字測試');--觸發條件  when條件滿足  刪除條件成立
end;
/
delete from emp where empno = 7369;--測試觸發器
rollback;--回滾操作
drop trigger tr_emp_before1;--刪除觸發器


--9.2.1 數據定義操作(DDL)觸發器。對象級操作 創建觸發器禁止對emp表的表結構進行修改
create or replace trigger tr_emp_ddl
before alter on schema
begin
  if dictionary_obj_name='EMP' and sysevent='ALTER' then   --傳值需要大寫!!!
     raise_application_error(-20001,'不允許修改emp表結構');
  end if;
end;
/
alter table emp add remark varchar2(200);--測試觸發器
drop trigger tr_emp_ddl;--刪除觸發器

--9.2.2 數據定義操作(DDL)觸發器。對象級操作 創建觸發器禁止對emp表的表結構進行修改,刪除
create or replace trigger tr_emp_ddl
before alter or drop on schema
begin
  if dictionary_obj_name='EMP' and sysevent='ALTER' then   --傳值需要大寫!!!
     raise_application_error(-20001,'不允許修改emp表結構');
  end if;
  if dictionary_obj_name='EMP' and sysevent='DROP' then   --傳值需要大寫!!!
     raise_application_error(-20001,'不允許刪除emp表結構');
  end if;
end;
/
alter table emp add remark varchar2(200);--測試觸發器
drop table emp;--測試觸發器
drop trigger tr_emp_ddl;--刪除觸發器

--9.2.3 數據定義操作(DDL)觸發器。 使用sys用戶  數據庫級操作   定義數據庫登陸觸發器
create table login_log--數據庫登陸日誌表
(
  logid     VARCHAR2(20),
  loginuser VARCHAR2(100),
  logindate DATE
);
create sequence loginseq;--創建登陸序列
create or replace trigger tr_db_ddl
after logon on database--logon 登陸操作
begin
  insert into login_log values(loginseq.nextval,sys.login_user,sysdate);
end;
/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章