Oracle學習筆記之觸發器

来源:http://www.cnblogs.com/lovetianjin/archive/2017/10/24/7721809.html
-Advertisement-
Play Games

觸發器 觸發器(trigger)是一些過程,與表關係密切,用於保護表中的數據,當一個基表被修改(INSERT、UPDATE或DELETE)時,觸發器自動執行,例如通過觸發器可實現多個表間數據的一致性和完整性。觸發器和應用程式無關。 觸發器的類型有三種: (1)DML觸發器。Oracle可以在DML( ...


                                                                                                             觸發器

觸發器(trigger)是一些過程,與表關係密切,用於保護表中的數據,當一個基表被修改(INSERT、UPDATE或DELETE)時,觸發器自動執行,例如通過觸發器可實現多個表間數據的一致性和完整性。觸發器和應用程式無關。

觸發器的類型有三種:

(1)DML觸發器。Oracle可以在DML(數據操縱語句)語句進行觸發,可以在DML操作前或操作後進行觸發,並且可以在每個行或該語句操作上進行觸發。

(2)替代觸發器。由於在Oracle中不能直接對有兩個以上的表建立的視圖進行操作,所以給出了替代觸發器。它是Oracle專門為進行視圖操作的一種處理方法。

(3)系統觸發器。在Oracle8i時,提供了第三種類型的觸發器叫系統觸發器。它可以在Oracle資料庫系統的時間中進行觸發,如Oracle資料庫的關閉或打開等。

創建觸發器有以下限制:

(1)代碼大小。觸發器代碼大小必須小於32K。

(2)觸發器中有效語句可以包括DML語句,但不能包括DDL語句。ROLLBACK、COMMIT、SAVEPOINT也不能使用。

(3)LONG、LONG RAW和LOB的限制:

①   不能插入數據到LONG或LONG RAW;

②   來自LONG或LONG RAW的數據可以轉換成字元型(如char、varchar2),但是不能超過32K;

③   使用LONG或LONG RAW不能聲明變數;

④   在LONG或LONG RAW列中不能使用:NEW和:PARENT;

⑤   在LOB中的:NEW變數不能修改。

每張基表最多可

建立12個觸發器,它們是:

(1)   BEFORE INSERT;

(2)   BEFORE INSERT FOR EACH ROW;

(3)   AFTER INSERT;

(4)   AFTER INSERT FOR EACH ROW;

(5)   BEFORE UPDATE;

(6)   BEFORE UPDATE FOR EACH ROW;

(7)   AFTER UPDATE;

(8)   AFTER UPDATE FOR EACH ROW;

(9)   BEFORE DELETE;

(10) BEFORE DELETE FOR EACH ROW;

(11) AFTER DELETE;

(12) AFTER DELETE FOR EACH ROW。


例如:做一個觸發器,當刪除dept表中部門時,將emp表中該部門人員信息清空;

createorreplacetrigger emp_dept

  afterdelete  on   dept

  foreachrow

declare

  

begin

deletefrom emp where emp.deptno=:old.deptno;

--表示刪除或者修改前該記錄舊的數據;

end emp_dept;

 

 例如:修改上題,要求將刪除的dept和emp表數據備份到指定表 deptOld和empOld表結構和dept、emp結構一致;

 createorreplacetrigger emp_dept

  afterdelete  on   dept

  foreachrow

declare

   cursor cur isselect*from emp where emp.deptno=:old.deptno;

   e emp%rowtype;

   department dept%rowtype;

  

begin

    deletefrom emp where emp.deptno=:old.deptno;

    ifsql%foundthen

       open cur;

       loop

            fetch  cur into e;

              insertinto empOld values(e.empno,e.ename,e.job,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno);

         exitwhen cur%notfound;

       endloop;

    endif;

           insertinto deptOld values(:old.deptno,:old.dname,:old.loc);

end emp_dept;

 

create or replace trigger deleteDeptTrigger

  after delete on dept 

  for each row

declare

   type cur_type is ref cursor;

   cur cur_type;

   emp_row emp%rowtype;

begin

   open cur for

   select * from emp where deptno=:old.deptno; 

 

   delete from emp where deptno=:old.deptno;

   loop

      fetch cur into emp_row;

      exit when cur%notfound;

      insert into empOld values(emp_row.empno,emp_row.ename,emp_row.job,emp_row.mgr,emp_row.hiredate,emp_row.sal,emp_row.comm,emp_row.deptno);

   end loop;

   close cur;

   insert into deptOld values(:old.deptno,:old.dname,:old.loc);

 

end deleteDeptTrigger;

 

305講解內容:

create or replace trigger deptTrigger

  after delete on dept 

  for each row

declare

  dept_deptno number(5);

  type cur is ref cursor return emp%rowtype;

  empcur cur;

  emprow emp%rowtype;

begin

       dept_deptno:=:old.deptno;

    open empcur for select * from emp where emp.deptno=dept_deptno;

    delete from emp where deptno=dept_deptno;

   

    loop

      fetch empcur into emprow;

      insert into oldemp values(e.nextval,emprow.empno,emprow.ename,emprow.job,emprow.mgr,emprow.hiredate,emprow.sal,emprow.comm,emprow.deptno);

      exit when empcur%notfound;

    end loop;

 

end deptTrigger;

創建替代(Instead_of)觸發器:

Instead_of用於對視圖的DML觸發。由於視圖有可能由多個表進行關聯(Join)而成,因

而並非所有的關聯都是可更新的。但是可以按如下例子來創建觸發器。

例如:

在scott資料庫中創建視圖和觸發器,以說明替代觸發器。

      CREATEORREPLACE VIEW emp_avgSalView

     AS   SELECT deptno,AVG(sal)   AS   avgSAL    FROM  emp

     GROUPby deptno;

創建該視圖的替代觸發器:

       CREATETRIGGER empAvgSalDel

    INSTEADOFDELETEON   emp_avgSalView  FOREACHROW

  BEGIN

    DELETEFROM  emp  WHERE  deptno=:OLD.deptno;

  END cs_kc_avg_del;

 

創建系統觸發器:

Oracle8i開始提供的系統觸發器可以在DDL或資料庫系統上被觸發。

DDL指的是數據定義語句,如CREATE、ALTER和DROP等。而數據

庫系統事件包括資料庫伺服器的啟動或關閉,用戶登錄與退出等。

--創建當一個用戶userA登錄時自動記錄一些信息的觸發器。

  CREATETRIGGER loguserAconnects

    AFTER LOGON ONSCHEMA

  BEGIN

    INSERTINTO LOGIN VALUES(‘userA’,’loguserAconnects fired’);

  END loguserAconnects;

 

面試題筆試題查詢:

1、通過case when行編列,列邊行;

2、刪除重覆行、留重覆行中的一行記錄。

3、Nvl和nvl2 區別

4、說出常用的10個資料庫函數

5、索引如何使用? 何時失效?

6、Sql語句級別的優化?

7、函數和存儲過程區別?

8、手寫存儲過程。

9、Oracle分頁語句和mysql分頁語句?

10、Rowid什麼是事務?

例如:查詢2000-3000之間的sal和、 4000-6000之間sal和、6000-8000sal和、

Select  sum(

Case when sal between 2000 and 3000

Then sal else 0 end

) ,sum(

 Case when sal between 4000and 6000

Then sal else 0 end

) from emp

Select  count(

Case when sal between 2000 and 3000

Then empno else null end

) ,count(

 Case when sal between 4000and 6000

Then empno else null end

) from emp

 

綜合實例:

模擬銀行匯款、取款、以及存款、餘額查詢操作:

Id、卡號、密碼、存款餘額

create table bankMsg( id number(15) primary key,cardno varchar2(20) unique not null,pwd varchar2(20) not null,

 money number(15,2)

);

Id、卡號、操作標示符(A存款、B取款、C轉賬)、操作時間、操作金額

create table bankMsgHistory(id number(5) primary key,cardno varchar2(20),

 flag varchar2(1),markDate date,money number(15,2)

)

 

寫一個函數驗證是否登陸成功;

寫一個存儲過程、用於操作存款、取款、轉賬以及餘額查詢;

(註意:由於觸發器獲取不到操作標示符因此不寫這個觸發器了)寫一個觸發器,當bankMsg表被修改以後,觸發操作記錄表數據新增;

登陸操作函數:

create or replace function bankLoginByCardno(cardno_param in varchar2,pwd_param in varchar2) return number is

    total number(5);

    flag number(1):=0;

begin

  select count(*) into total from bankMsg where cardno =cardno_param and pwd=pwd_param; 

  if total >0 then

    flag:=1;

  end if ;

  return flag;

end bankLoginByCardno;

存儲過程:

--該存儲過程,根據用戶名密碼登陸, 卡號為用戶名,pwd自定義,

--根據操作標示Flag (A存款、B取款、C轉賬) 對銀行卡信息數據進行修改, 然後觸發記錄表記錄操作記錄

/*

 username :用戶名

 pwd:密碼

 controlFlag操作標示符

 money金額

 targetCardno對方卡號

 succssOrError 是否操作成功,1 成功,0 失敗

 errorMsg 操作失敗原因out類型參數

 showMsg 查詢餘額信息的out類型變數

*/

create or replace procedure userBankCardnoMsg(username in varchar2, pwd in varchar2,

controlFlag in varchar2,money_param in number,targetCardno in varchar2,successOrError out number,

errorMsg out varchar2,

showMsg out bankMsg%rowType

) is

 flag number(5):=0;

 flag2 number(5):=0;

 money number(15,2);

begin

  successOrError:=0;--成功失敗標示符預設為0

  flag:=bankloginbycardno(username,pwd);

 -- money_param:=nvl(money_param,0);

  if flag=1 then--登陸成功

     select money into money from bankMsg where cardno=username;

     case controlFlag

       when 'A' then--存款

             update bankMsg set money=money+money_param    where cardno=username;--修改金額

             insert into bankMsgHistory values(bankcardno_seq.nextval,username,controlFlag,sysdate,money_param);

             successOrError:=1;

             errorMsg:='存款成功';

             select * into showMsg from bankMsg where cardno=username;

       when 'B' then--取款

            if money>=money_param then--判斷是否有足夠餘額

                update bankMsg set money=money-money_param    where cardno=username;--修改金額

                insert into bankMsgHistory values(bankcardno_seq.nextval,username,controlFlag,sysdate,money_param);

                successOrError:=1;

                errorMsg:='取款成功';

                select * into showMsg from bankMsg where cardno=username;

            else

                successOrError:=0;

                errorMsg:='取款失敗,餘額不足';

            end if;

                

       when 'C' then--轉賬

             select count(*) into flag2 from bankMsg where  cardno=targetCardno;--查看目標賬號是否存在

              if flag2<=0 then

                 successOrError:=0;

                  errorMsg:='轉賬失敗,目標卡號不存在';

               else

                              

                  if money>=money_param then--判斷是否有足夠餘額

                        update bankMsg set money=money-money_param    where cardno=username;--修改金額

                        insert into bankMsgHistory values(bankcardno_seq.nextval,username,controlFlag,sysdate,money_param);

                        update bankMsg set money=money+money_param where cardno=targetCardno;--修改目標賬號金額

                        insert into bankMsgHistory values(bankcardno_seq.nextval,targetCardno,'A',sysdate,money_param);

                        successOrError:=1;

                        errorMsg:='轉賬成功';

                        select * into showMsg from bankMsg where cardno=username;

                  else

                        successOrError:=0;

                        errorMsg:='轉賬失敗,餘額不足';

                 end if;

              

               end if;

            

      

        when 'D' then --查看餘額

             select * into showMsg from bankMsg where cardno=username;

              successOrError:=1;

              errorMsg:='查詢操作成功';

        else

          successOrError:=0;

          errorMsg:='操作失敗';

        end case;

      

      else

          successOrError:=0;

          errorMsg:='登陸失敗';

     

      

        

  end if;

 

 

end userBankCardnoMsg;

測試代碼:

-- Created on 2017/10/23 by ADMINISTRATOR

declare

    successFlag number(1);

    errorMsg varchar2(50);

    showMsg  bankMsg%rowType;

begin

  -- Test statements here

   /*

   --測試存款

   userBankCardnoMsg('111111','123','A',10,null,successFlag,errorMsg,showMsg);

 if successFlag=1 then

    dbms_output.put_line(errorMsg);

    dbms_output.put_line('卡號:'||showMsg.Cardno||'餘額'||showMsg.Money);

  else

    dbms_output.put_line(errorMsg);

  end if;

  */

  /*--測試取款

   userBankCardnoMsg('111111','123','B',10,null,successFlag,errorMsg,showMsg);

 if successFlag=1 then

    dbms_output.put_line(errorMsg);

    dbms_output.put_line('卡號:'||showMsg.Cardno||'餘額'||showMsg.Money);

  else

    dbms_output.put_line(errorMsg);

  end if;

  */

 

  /*--測試轉賬

   userBankCardnoMsg('123321','123','C',10,'12321',successFlag,errorMsg,showMsg);

 if successFlag=1 then

    dbms_output.put_line(errorMsg);

    dbms_output.put_line('卡號:'||showMsg.Cardno||'餘額'||showMsg.Money);

  else

    dbms_output.put_line(errorMsg);

  end if;

  */

  --測試查詢餘額

   userBankCardnoMsg('222222','123','D',0,null,successFlag,errorMsg,showMsg);

 if successFlag=1 then

    dbms_output.put_line(errorMsg);

    dbms_output.put_line('卡號:'||showMsg.Cardno||'餘額'||showMsg.Money);

  else

    dbms_output.put_line(errorMsg);

  end if;

 

end;

 

 

--------------------例子-----------------------------

存儲過程:

create or replace procedure Test_emp(username in varchar2,pwd in varchar2, flag in varchar2,res out p_1.cur_type,msg out varchar2 )

is f boolean;

begin

   f:=test_login(username,pwd);

  if f then--驗證通過

       case when flag='1' then--查詢所有數據

          open res for select * from emp;

          msg:='查詢所有記錄成功';

       when flag='2' then--查詢當前數據

          open res for select * from emp where emp.ename=username and emp.empno=pwd;

            msg:='查詢當前記錄成功';

       when flag='3' then--清空emp表

           delete from emp;

            msg:='截斷表成功';

       end case;

  else

     msg:='驗證不通過';

  end if;

end Test_emp;

 

----自定義函數:

create or replace function Test_login(username in varchar2,pwd in varchar2) return boolean is

  Result boolean  ;

  total integer;

begin

  select count(*) into total from emp where emp.ename=username and emp.empno=pwd; 

  if total>0 then

    return true;

  else

    return false;

  end if;

end Test_login;

 

-------測試----------

-- Created on 2015/3/24 by ADMINISTRATOR

declare

   res p_1.cur_type;

   msg varchar2(200);

   flag varchar2(1):='3';

   r emp%rowtype;

begin

   test_emp('SMITH','7369',flag,res,msg);

   dbms_output.put_line(msg);

   if flag='1' then

   

      loop

           fetch res into r;

        exit when res%notfound;

     

          dbms_output.put_line(r.empno||r.ename||r.hiredate);

      end loop;

   elsif flag='2' then

       loop

          fetch res into r;

        exit when res%notfound;

      

          dbms_output.put_line(r.empno||r.ename||r.hiredate);

      end loop;

   elsif flag='3' then

    null;

   end if;

   exception when others then null;

end;

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java習題10.24 1、 1,3.connect()與accept():這兩個系統調用用於完成一個完整相關的建立,其中connect()用於建立連接。accept()用於使伺服器等待來自某客戶進程的實際連接。 2.listen():此調用用於面向連接伺服器,表明它願意接收連接。listen()需 ...
  • 通常,所有的玩家的操作都會經過玩家進程去處理。那麼當玩家的操作很多的時候 該怎麼去設計劃分呢?(比如你有任務模塊、充值模塊、不同玩法模塊的時候)。 在以前的項目中,大家是這麼做的,以數字編碼模塊, 比如 handle(1xxxxx) 處理登錄 handle(2XXXX)處理任務等等。 然後1xxxx ...
  • "條記錄", 'prev' => "上一頁", 'next' => "下一頁", 'first'=> "首頁", 'last' => "末頁" ); //在分頁信息中顯示內容,可... ...
  • 參考:【Python yield 使用淺析】、【Python xrange與range的區別】等 一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用 next()(在 for 迴圈中會自動調 ...
  • 數組的定義:是用統一的名字代表這批數據,用序號來區分各個數據。數組是有序數據的集合。 如何理解:其實就是一個同時放很多數據的變數。 如 int a0;int a1; int a2; a=1; a=2; a=3; 這成了反覆賦值,最後a=3; a怎麼能同時放下1,2,3......? 必須是同樣的數據 ...
  • 一、前言 在工作中,難免遇到各種各樣的問題,每個人似乎都有一套自己的解決方案。而我,又不想每次解決完問題就把東西扔了,撿了芝麻,丟了西瓜,什麼時候才能進步勒?學習要靠積累,畢竟量變才能引起質變嘛。所以寫了這篇博文,不定時更新自己項目中遇到的問題、踩過的那些坑...... 二、項目 1、Java 將兩 ...
  • 引言 Sun所指定的JavaBean規範很大程度上是為IDE準備的 它讓IDE能夠以可視化的方式設置JavaBean的屬性。如果在IDE中開發一個可視化的應用程式,則需要通過屬性設置的方式對組成應用的各種組件進行定製,IDE通過屬性編輯器讓開發人員使用可視化的方式設置組件的屬性。 一般的IDE都支持 ...
  • 函數外部聲明有什麼作用? 讓我們定義的函數應用範圍更廣,生命更長久。共用。 也就是說所有的外部函數都可以直接調用。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...