張未未,王蘋,杜清
觸發器(Trigger)是用戶定義在關系表上的一類由事件驅動的特殊過程。一旦定義,任何用戶對表的增、刪、改操作均由服務器自動激活相應的觸發器,在DBMS核心層進行集中的完整性控制[1]。觸發器類似于約束,但是比約束更加靈活,可以實施比FOREIGN KEY約束、CHECK約束更為復雜的檢查和操作,具有更精細和更強大的數據控制能力[2-3]。
Microsoft Access是一種小型的關系數據庫管理系統,也被稱之為桌面型數據庫。作為Microsoft Office重要成員之一,由于 Access提供了基本數據庫管理功能和強大易用的應用擴展能力,而備受小型企事業數據管理者和數據庫初學者的青睞。但在實現數據完整性控制方面,Access所提供的更多的是聲明性數據完整性機制,例如:主鍵、默認值、有效性規則、表間關系等,而一直以來并沒有提供在過程性數據完整性方面的擴展,特別是對于觸發器機制的支持。但自Office 2010之后,Access數據庫中增加了一種新的宏類型—數據宏,用以實現類似觸發器的功能,從而極大地完善了Access數據庫的功能。
由于數據宏是由表事件觸發而執行的,因此,也可以稱之為“事件驅動的數據宏”。數據宏允許在表事件(如插入、更新或刪除數據等)中運行宏操作。每當在表中添加、更新或刪除數據時,都會發生對應的表事件,數據宏可以在發生這3種事件中的任何一種事件之后,或在發生刪除或更改事件之前運行[4]。
Access中,數據宏按照被激活的時機不同,分為前期事件數據宏和后期事件數據宏,如圖1所示:

圖1 數據宏的分類
前期事件數據宏中宏操作在數據修改事件發生、但還未保存之前被觸發執行,用以實現數據修改的完整性邏輯驗證[5]。在前期事件數據宏中可以決定數據是否允許被真正修改,還是顯示錯誤以停止修改。
前期事件數據宏根據觸發的事件不同又可以分為更改(Update)前數據宏和刪除(Delete)前數據宏。
(1)更改前數據宏
更改前數據宏在記錄更改動作發生且保存記錄之前運行,通常用來進行邏輯驗證,以決定記錄是否允許被修改或顯示錯誤以停止修改。
(2)刪除前數據宏
刪除前數據宏在記錄刪除動作發生且記錄被真正刪除之前運行,通常用來進行邏輯驗證,以決定記錄是否允許被刪除或顯示錯誤以停止刪除。
后期事件數據宏中宏操作在數據修改事件發生,且修改已保存之后被觸發執行,用以實現數據表中不同字段以及不同數據表間數據的連動更新[6]。
后期事件數據宏根據觸發的事件不同又可以分為插入(Insert)后數據宏、更新(Update)后數據宏和刪除(Delete)后數據宏。
(1)插入后數據宏
插入后數據宏是指在新記錄被添加到表后所運行的邏輯。
(2)更新后數據宏
更新后數據宏是指在現有記錄被更改后所運行的邏輯。
(3)刪除后數據宏
刪除后數據宏是指在記錄被刪除后所運行的邏輯。
[舊]或[Old]記錄集:該記錄集用于臨時保存表中被更改或刪除的記錄在更改或刪除前的值。可以通過[舊].
[FieldName]來獲取不同字段的“舊”值。該對象通常用于更新后數據宏和刪除后數據宏[7]。
Updated(“Field Name”)函數用來判斷某個字段的值是否已更改。該函數通常用于更新后數據宏,可用于區分在不同字段值被更新后選擇執行不同的宏操作。
如表1所示:

表1 數據宏常用操作
如圖2所示:

圖2 更新后數據宏舉例
當將某記錄的“項目狀態”字段中的值設置為“未開始”時,則該記錄的“完成百分比”字段中的值會自動更改為0%;而“項目狀態”字段的值由“進行中”改為“完成”時,則“完成百分比”字段中的值會自動更改為100%。該例所實現的效果是同一數據表中某一字段數據被更改后,其他字段數據的連動更新,因此,可以為“項目”數據表添加更新后數據宏。本例是微軟官方給出的數據宏應用實例。
官方宏操作代碼如圖3(圖中加粗部分為數據宏各操作中的必須組成)所示:

圖3 更新后數據宏實例微軟官方代碼
但筆者執行后并沒有發生預期的改變,而且在 Access的“應用程序日志表”中會增加一條錯誤信息,提示“由于默認別名表示的記錄處于只讀狀態”。經過筆者反復試驗發現問題出現在“EditRecord”操作的“別名”參數上,如圖4所示:

圖4 更新后數據宏對于被更改記錄的處理
當在表中修改某一記錄的字段值時,系統會把當前修改后的記錄映射為一個臨時的記錄集,并為此記錄集起一個“默認別名”(“默認別名”就是當前修改記錄所在表的名字,對于本例來說“默認別名”為“項目”),通過此別名,可以在數據宏中對于臨時記錄集進行調用,從而得到該記錄修改后各字段的值。特別注意的是該臨時記錄集為只讀,而不能被修改。
而在數據宏的“EditRecord”操作中,由“別名”所指代的記錄集中的記錄將被修改。如果“別名”參數不寫,則表示使用“默認別名”所代表的記錄集,而該記錄集是只讀的,因此,就會出現“由于默認別名表示的記錄處于只讀狀態”的錯誤信息,從而導致數據宏“EditRecord”操作失敗。圖3所給出的微軟官方代碼是不能達到預期效果的。很多初次接觸數據宏的應用開發人員會被這個例子所誤導,而誤以為Access中的數據宏是不起作用的。
圖3所示代碼修改后如圖5所示:

圖5 更新后數據宏實例修改后代碼
修改后的代碼加入了“Updated("項目狀態")”函數用以判斷只有當“項目狀態”這個字段被更新時才執行后續宏操作,而其他字段更新不會執行該宏,從而可以提高宏代碼效率。而“查找所選對象中的記錄”,即 LookupRecord操作是用來重新定位當前被更改的記錄,在查找過程中使用了條件“[ID]=[舊].[ID]”。如前所述,“[舊]”記錄集保存了被更改的記錄在更改前的各字段的值,而對于“[ID]”字段實際是沒有進行更改的,即被更改的記錄更新前后“[ID]”字段的值是一樣的。因此,可以據此條件在“項目”表中重新找到被更新的記錄,并形成名為“當前更新記錄”的臨時記錄集。而這個記錄集是可讀寫的,因此,可以通過該記錄集完成對于表中其他字段值地修改。
Access數據庫中存在“tbl班級”和“tbl學生”兩張表,如圖6所示:

圖6 “tbl班級”表和“tbl學生”表
通過以“班級編號”字段為外鍵可以建立兩張表之間一對多的關系,從而限制“tbl學生”表中的班級編號的取值必須來自“tbl班級”表中已有的班級編號。但如果要使“tbl班級”表中“班長”字段中的學生編號必須是來自該班的學生的學生編號,即必須是本班的學生才有資格擔任本班的班長,這樣的表間數據約束是不能通過外鍵約束來實現的,因此可以考慮使用數據宏。由于當在“班長”字段中輸入數據,還未保存時就必須判斷是否符合要求,如果不符合要求將會顯示錯誤信息同時停止數據更改,所以為“tbl班級”表加入更改前數據宏[8]。
為“tbl班級”表添加“更改前數據宏”代碼如圖7所示:

圖7 更改前數據宏實例代碼
本例所實現的是過程性完整性約束,驗證思路如圖 8所示:

圖8 更改前數據宏驗證過程
通過“查找所選對象中的記錄”操作找到“新班長”學號在“tbl學生”表中的記錄,比較一下該記錄中的“班級編號”是不是與正在修改的班級的“班級編號”相同。如果不同說明“新班長”并不是當前班的學生,沒有資格成為班長。這里注意,“tbl班級”是用默認別名來表示修改后的數據所形成的記錄集。因此“[tbl班級].[班長]”可以得到修改后班長的學號。
使用“RaiseError”操作顯示錯誤信息,并可以撤銷對于字段數據的修改。操作后提示的錯誤信息如圖9所示:

圖9 更改前數據宏實例錯誤信息
通過以上實例不難發現,對于數據宏的使用關鍵要把握住“[舊]”記錄集和“默認別名”(以表名為默認別名)記錄集的意義:
(1)“[舊]”記錄集用于臨時保存表中被更改或刪除的記錄在更改或刪除前的值。
(2)“默認別名”記錄集用于臨時保存表中被更改的記錄在更改后的新值。
通過數據宏的使用可以在Access中實現類似于大型數據庫中觸發器的功能,從而實現過程性數據完整性定義和更加復雜的數據邏輯約束,可謂是 Access數據庫的一項重大改進。在使用中應注意特殊記錄集、函數和常用操作的功能,特別是數據修改時“別名”的使用,以達到正確書寫宏操作代碼的目的。
[1] 王珊,薩師煊.數據庫系統概論(第四版)[M].北京:高等教育出版社,2008.
[2] 嚴永慧.基于MS Office的企業項目管理系統的設計[J].微型電腦應用,2013,29(4):12-15.
[3] 肖海蓉.觸發器技術在數據庫系統開發中的應用研究[J].電腦開發與應用,2011,24(7):36-38.
[4] 馬星光,劉仁權.Access2010中醫藥數據庫實例教程[M].北京:中國中醫藥出版社,2012.
[5] 褚龍現.DML觸發器保持數據庫完整性應用研究[J].計算機與現代化,2013(4):57-59.
[6] 胡鶴年.SQL Server觸發器在數據庫設計中的應用[J].數據庫與信息管理,2012(8):37-38,83.
[7] http://msdn.microsoft.com/zh-cn/library/f?f973807(-v=office.14).aspx
[8] 汪星輝.基于 Access的教務管理系統的設計與應用[J].計算機光盤軟件與應用,2013(20):282-284.