<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    簡介

    當特定事件在 IBM® DB2® Universal Database™ 數據庫中發生時,您就可以激活 觸發器來執行其他一些操作。在本文中,您將在觸發器的世界里遨游,看看如何通過觸發器來增強數據庫中的業務規則。您還將學習如何使用 DB2 UDB Version 8.1 的控制中心來幫助您創建一個應用于簡單業務場景的簡單觸發器。

    什么是觸發器

    當一個指定的 SQL 操作(如 DELETE,INSERT,或者是 UPDATE 操作)作用于某張表時,一個定義了一組操作的觸發器就可以被激活。觸發器并不像參照完整性約束和檢查約束那樣,我們甚至可以使用對其他表來進行更新。

    業務場景

    將一項技術應用于真實世界的一個場景總是有益的。出于教學的目的,讓我們在一個銀行相關環境中研究觸發器,在該模擬環境中,我們僅僅建立了一張表。再次強調,這是被簡化了的!我們將要做的是,運用觸發器來促進銀行提供的透支保護。例如,一個銀行客戶有一個支票帳戶(checking account)和一個儲蓄帳戶(saving account)。當從支票帳戶中取款的金額超過了該帳戶的余額時,就會發生一次自動的轉帳(叫做透支保護),即自動從客戶的儲蓄帳戶轉帳過來。當然,這必須符合一定的條件,即儲蓄帳戶中必須有足夠多的錢來補償透支的金額。

    開始

    像上面所提及的,我們的銀行僅僅包含一張表。在這張表中,我們將存入客戶的支票帳戶和儲蓄帳戶的余額等信息。每個客戶通過其社會保險號碼來標識。下面是對該表的描述:

    表 1. 對 ACCTTABLE 的描述

    Column Name Column Type Nullable?
    SSN* Varchar(11) NO
    LastName Varchar(30) NO
    FirstName Varchar(30) NO
    SavingBalance Decimal (Precision: 7, Scale: 2) NO
    CheckingBalance Decimal (Precision: 7, Scale: 2) NO
    * 表示主鍵

    請使用 DB2 命令行處理器為上面的表創建一個數據庫。將數據庫命名為 bnkdb。

    db2 => create database bnkdb

    接下來,連接到該數據庫。我假設您已經在您的機器上有了一個用戶名為 db2admin 密碼為 db2admin 的帳號。

    db2 => connect to bnkdb user db2admin using db2admin

    現在,創建 accttable 表:

    db2 => create table accttable(ssn varchar(30) not null primary key,
                lastname varchar(30) not null, firstname varchar(30) not null,
                savingbalance decimal(7,2) not null, checkingbalance decimal(7,2) not null)
                

    現在向所創建的表中加入兩條記錄:

    db2 => insert into accttable values
                ('111-11-1111','Bhogal','Kulvir',1500.00,1000)
                
    db2 => insert into accttable values
                ('222-22-2222','Guy','Someother',2000.00,4000)
                

    觸發器可以在對表的一次 INSERT、 DELETE 或者 UPDATE 操作 之前之后啟動。在我們的例子中,您將創建一個在對ACCTTABLE 表執行 UPDATE 操作之前啟動的觸發器。在觸發器術語中,INSERT、 DELETE 或者 UPDATE 這些使得觸發器啟動的事件被稱作 觸發事件。觸發器的啟動是在觸發事件之前還是之后則稱為觸發器的 激活時間

    使用 Control Center 創建觸發器

    打開 DB2 Control Center 開始創建觸發器,展開您創建的數據庫(即 bnkdb),鼠標右鍵點擊 Triggers 選項并且選擇 Create.....

    圖 1. 創建觸發器

    Figure 1.

    Create Trigger 屏幕中,可以指定觸發器所在的模式。請選擇 DB2ADMIN 模式。記住,觸發器是與表相關的,所以我們需要選擇相關表的模式。然后請再次選擇 DB2ADMIN 模式:

    圖 2. 選擇模式

    Figure 2.

    在同一個屏幕中, 需要指定一個觸發器的名字。將觸發器命名為 OVERDRAFT。而且,需要指定與該觸發器相關的表的名字。這里選擇您創建的 ACCTTABLE

    圖 3. 選擇您創建的表

    Figure 3.

    Time to trigger action區域中,選擇 Before

    圖 4. 選擇 Before

    Figure 4.

    Operation that causes the trigger to be executed區域中選擇 Update of columns 操作并且指定被操作列為 CHECKINGBALANCE

    圖 5.

    Figure 5. Specify the column name

    點擊 Triggered action標簽頁來創建該觸發器:

    圖 6. 構建觸發器

    Figure 6.

    指定臨時變量

    DB2 UDB 能夠跟蹤在啟動觸發器的那條語句之前和之后的一行的狀態。請在 Correlation name for the old rows 一欄中填入 OLDROW,Correlation name for the new rows 一欄中填入 NEWROW

    圖 7. 指定 NEWROW

    Figure 7.

    注意,您也許無法指定其中的一個 correlation name,因為它依賴于引起觸發器啟動的特定操作和激活時間的組合。例如,假設您的觸發器選擇的 Time to trigger actionBefore,觸發事件是 DELETE 語句。在這種情況下,我們就無法指定一個 "Correlation name for the new rows"。為什么呢?因為在執行了一個刪除操作以后,新行是不存在的。

    因為您創建的觸發器是在 UPDATE 之前被激活,所以不能編輯 Temporary table for the old rowsTemporary table for the new rows選項。

    您將注意到,在這種情況下(一個在 UPDATE 之前被激活的觸發器),您只能指定觸發器針對 而不是針對每個 語句觸發。

    圖 8. 觸發器觸發于每行

    Figure 8.

    引起觸發事件的語句可能會同時影響數據庫中的多行。"For each Row" 選項意味著觸發器將在每一行被修改時激活。另一方面,"For each statement" 選項("before" 型觸發器是不允許的)則意味著觸發器定義的操作只在調用一次 SQL 語句后執行一次。

    可以點擊 Show SQL按鈕來看看底層的 SQL 語句到目前為止是什么樣子:

    圖 9. Show SQL 框

    Figure 9.

    構建觸發動作

    現在該創建觸發動作了。我們的業務規則是支票帳戶的余額必須低于 0 才能激活該觸發器。也就是說,我們需要指定 search-condition 為 NEWROW.CHECKINGBALANCE<0 。我們之所以指定 NEWROW.CHECKINGBALANCE 是因為需要分析在 update 操作之后支票帳戶的余額將會是多少。

    創建觸發器主體

    現在我們將要在 Triggered Action 文本區域中替換 triggered-SQL-statement (參見下面)。

    圖 10. 創建觸發器語句

    Figure 10.

    用來替換的代碼如下:

    declare overage decimal (7,2);
                set overage = (NEWROW.CHECKINGBALANCE*-1);
                if overage>OLDROW.SAVINGBALANCE then SIGNAL SQLSTATE '70001'
                ('Overdraft Protection Unsuccessful');
                else set newrow.savingbalance =
                oldrow.savingbalance-overage, newrow.checkingbalance = 0;
                end if;
                

    讓我們一句一句地仔細研究一下這段代碼。在觸發器主體中,可以聲明將要在主體中使用的變量。我們使用下面這行代碼來聲明變量: decimal(7,2)declare overage decimal (7,2) ; 這樣就定義了一個類型為 decimal(7,2) 名為 overage 的變量。

    下一步我們將 overage 變量的值設置為 (NEWROW.CHECKINGBALANCE*-1) ;

    我們將使用該算式計算出我們想要從支票帳戶取出的超額(overage)的數目。指定 NEWROW.CHECKINGBALANCE 是因為我們需要分析支票帳戶的余額在 update 操作發生后是多少。

    set overage = (NEWROW.CHECKINGBALANCE*-1);

    發出錯誤條件信號

    如果違反了您在觸發器中定義的業務規則,就可以使用 SIGNAL 語句來拋出一個錯誤條件信號。在我們的例子中,不允許有人擁有的支票帳戶余額為負數。如果有人想要將支票帳戶的余額列更新為一個負數,我們就可以試著看看在儲蓄帳戶中是否有足夠多的錢來補償這個負數。如果沒有,那么就可以發出一條 SQL 狀態為 '70001' 的信息 "'Overdraft Protection Unsuccessful"。

    認識到包含 SIGNAL 語句的效果是很重要的。SIGNAL 語句回滾由觸發語句(也就是我們的 update 語句)嘗試的更改。SIGNAL 語句也將回滾在觸發器內發生的更改。此外,假設我們是使用 Java™ 應用程序來與數據庫進行交互的,并且試圖執行一次會觸發我們的觸發器并違反業務規則的 update 操作。Java 應用程序將接受我們所指定的 SQLSTATE 以及值為 -438 的 SQLCODE。在這行中我們使用 SIGNAL SQLSTATE 屬性:

    if overage>OLDROW.SAVINGBALANCE then SIGNAL SQLSTATE '70001'
                ('Overdraft Protection Unsuccessful');
                

    該行說明,如果我們的 overage 比儲蓄帳戶的余額數目還要大,那么就需要拋出一個危險信號。

    轉帳

    如果儲蓄帳戶的余額數目足夠補償超出的數目,這時就會發生轉帳。如果滿足這種條件,我們將對新行作兩處修改:

    1. 修改 "new row" 的 savingbalance 列,將其減去 overage 以促成透支轉帳。
    2. 將支票帳戶的余額設置為 0。我們使用下面的代碼來完成:

    
                else set newrow.savingbalance = oldrow.savingbalance-overage,
                newrow.checkingbalance = 0; end if;
                

    最終結果

    可以再次通過 Show SQL按鈕來看看最后的結果:

    圖 11.顯示 SQL

    Figure 11.

    在點擊 Close之后,您將看到 OVERDRAFT 觸發器已經創建好了:

    圖 12. 創建 OVERDRAFT 觸發器

    Figure 12.

    測試

    可以通過一個 update 語句來進行測試。打開命令行編寫下面的語句:

    db2=> update accttable set checkingbalance = -500 where ssn='111-11-1111'
                

    根據我們創建的業務邏輯,這個 update 操作將啟動該觸發器,由于支票帳戶透支,該觸發器將從 savingbalance 列取出 500.00 到支票帳戶。因此,SSN 為 111-11-1111 的帳戶的 checkingbalance 會變成 0.00 而 savingbalance 將變成 1000.00(原來的余額 1500 - 透支的 500)。下面的查詢驗證了該結果:

    圖 13. 查詢

    Figure 13.

    尾聲

    您已經在一個假想的業務場景中創建了一個 DB2 觸發器。觸發器是 DB2 數據庫的一個非常強大的特性,您可以使用它將業務邏輯分化到關系數據庫這邊。如果考慮到有多個應用程序都將與同一個數據庫進行交互,您就會發現這種分化是非常強大的。在一個大型企業中,您可能多次遇到過這樣的情況,即不知道要創建的是怎樣一個將與數據庫交互的應用程序。與其只是希望這些應用程序遵守被認為是您的組織機構的戒律的業務規則,還不如使用觸發器作為您工具箱中的一種工具,以確保現在和將來與數據庫進行交互的所有的應用程序強制遵守這些業務規則。一個觸發器只能關聯一個表,而不能關聯一個視圖。您也許可以考慮使用 INSTEAD OF 觸發器來與視圖交互。


    posted on 2007-07-24 15:47 蘆葦 閱讀(1463) 評論(2)  編輯  收藏 所屬分類: 數據庫IBM

    Feedback

    # re: 在DB2中創建第一個觸發器 2007-07-24 15:52 蘆葦
    我自己曾用到的:
    --建觸發器
    --
    修改登錄人信息觸發
    create trigger db2admin.t_userlogin_upd after update on db2admin.USER_LOGIN referencing new as n  old AS o for each row
    begin atomic
      
    declare TEMP_IBMSNAP_COMMITSEQ bigint;
      
    IF ((n.WORK_ID <> o.WORK_ID) or (n.USER_LOGIN_ID <> o.USER_LOGIN_ID) or (n.CURRENT_PASSWORD <> o.CURRENT_PASSWORD)) THEN      
        
    set TEMP_IBMSNAP_COMMITSEQ = nextval for db2admin.seq_name;
        
    INSERT INTO db2admin.CCD_USER_LDAP VALUES (TEMP_IBMSNAP_COMMITSEQ, 0'U', n.PARTY_ID, n.USER_LOGIN_ID , n.CURRENT_PASSWORD , 'CLERK_NAME' , n.WORK_ID , '1' );
          
    UPDATE db2admin.CCD_USER_LDAP SET CLERK_NAME = (select CLERK_NAME from CLERK where PARTY_ID =n.PARTY_ID) where IBMSNAP_COMMITSEQ = TEMP_IBMSNAP_COMMITSEQ;
      
    end if;
    end


    --新增登錄人信息觸發
    create trigger db2admin.t_userlogin_ins after insert on db2admin.USER_LOGIN referencing new as n for each row 
    begin atomic
        
    declare TEMP_IBMSNAP_COMMITSEQ bigint;
        
    set TEMP_IBMSNAP_COMMITSEQ = nextval for db2admin.seq_name;
       
    INSERT INTO db2admin.CCD_USER_LDAP VALUES (TEMP_IBMSNAP_COMMITSEQ, 0'I', n.PARTY_ID, n.USER_LOGIN_ID , n.CURRENT_PASSWORD , 'CLERK_NAME' , null , '1');
       
    UPDATE db2admin.CCD_USER_LDAP SET CLERK_NAME = (select CLERK_NAME from CLERK where PARTY_ID =n.PARTY_ID) where IBMSNAP_COMMITSEQ = TEMP_IBMSNAP_COMMITSEQ;
    end

    --修改登錄人姓名或狀態觸發
    create trigger db2admin.t_userinfo_upd after update on db2admin.CLERK referencing new as n  old AS o for each row
    begin atomic
      
    declare TEMP_IBMSNAP_COMMITSEQ bigint;
      
    IF ((n.CLERK_NAME <> o.CLERK_NAME) or (n.CLERK_STATUS <> o.CLERK_STATUS)) THEN         
        
    set TEMP_IBMSNAP_COMMITSEQ = nextval for db2admin.seq_name;
        
    INSERT INTO db2admin.CCD_USER_LDAP VALUES (TEMP_IBMSNAP_COMMITSEQ, 0'U', n.PARTY_ID, 'USER_LOGIN_ID' , 'CURRENT_PASSWORD'  , n.CLERK_NAME , 'WORK_ID''0' );
          
    UPDATE db2admin.CCD_USER_LDAP SET USER_LOGIN_ID = (select USER_LOGIN_ID from USER_LOGIN where PARTY_ID =n.PARTY_ID),CURRENT_PASSWORD=(select CURRENT_PASSWORD from USER_LOGIN where PARTY_ID =n.PARTY_ID),WORK_ID=(select WORK_ID from USER_LOGIN where PARTY_ID =n.PARTY_ID) where IBMSNAP_COMMITSEQ = TEMP_IBMSNAP_COMMITSEQ;
      
    end if;
    end

    --刪除觸發器
    DROP TRIGGER DB2ADMIN.T_USERLOGIN_INS;
    DROP TRIGGER db2admin.T_USERLOGIN_UPD;
    DROP TRIGGER db2admin.T_USERINFO_UPD;
    --創建一個sequence 
    create sequence seq_name start with 1 increment by 1 
    --刪除sequence
    drop sequence seq_name
      回復  更多評論
      

    # re: 在DB2中創建第一個觸發器 2007-07-24 15:59 蘆葦
    sequence是一種方法。也可以用用indentity列
    CREATE TABLE table (col1 INT,
    col2 DOUBLE,
    col3 INT NOT NULL GENERATED ALWAYS AS IDENTITY
    (START WITH 100, INCREMENT BY 5))   回復  更多評論
      

    主站蜘蛛池模板: 日本一区二区免费看| 久久精品免费一区二区喷潮| 亚洲免费视频网站| 无码免费午夜福利片在线| 国产成人 亚洲欧洲| 亚洲AV无码乱码国产麻豆穿越| 亚洲w码欧洲s码免费| 色噜噜噜噜亚洲第一| 婷婷久久久亚洲欧洲日产国码AV| 久久精品a一国产成人免费网站| 一区二区三区免费精品视频| 亚洲伊人久久大香线蕉影院| 亚洲国产av无码精品| 3344免费播放观看视频| 四虎永久在线精品免费一区二区| 91亚洲国产成人久久精品网站| 免费人成视频在线观看视频| 美丽姑娘免费观看在线观看中文版| 久久精品国产亚洲AV电影网| 337p欧洲亚洲大胆艺术| 亚洲一区二区三区在线视频| 久九九精品免费视频| 你好老叔电影观看免费| 亚洲AV永久无码精品放毛片| 亚洲AV第一页国产精品| 亚洲AV无码专区日韩| 97无码免费人妻超级碰碰碰碰| 中文字幕免费观看视频| 国产成人亚洲午夜电影| 亚洲国产理论片在线播放| 久久99国产亚洲高清观看首页| 国产麻豆免费观看91| 久热中文字幕在线精品免费| 国产在线播放线91免费| 污网站在线免费观看| 亚洲熟女综合色一区二区三区| 亚洲AV色香蕉一区二区| 亚洲午夜久久久影院伊人 | 日韩亚洲变态另类中文| 免费观看国产精品| 美女被免费视频网站a国产|