张未未,王苹,杜清
触发器(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.