罗颖,屈俊峰
(湖北文理学院数学与计算机科学学院,襄阳 441053)
MS SQL Server数据库管理系统提供了一套完整性规则的定义,包括实体完整性、参照完整性和用户定义的完整性来维护数据库中数据的正确性和相容性。这3类完整性定义在基本表上,只能实现基本的完整性维护功能,如:确保主键数据不重复非空、实现字段有效性和唯一性的检查、自动填入默认值、确保数据表之间引用(即外键)的一致性等功能。但是以下2种情况是上述3类完整性没有办法实现的。
(1)当一个表中有汇总字段时,该汇总字段值是通过该表中其他字段值计算得出的。每当向该表插入记录时,新插入记录的汇总字段值必须由该记录上相应的其他字段数据计算得出。
(2)对于两个相关联的表,其中一个表的数据改变时,另一个表中相关联的数据也必须随着更新,即数据联动,否则数据就不正确了。
在上述2种情况下,定义相应的触发器来维护特殊的计算要求和数据联动等复杂的业务逻辑是必要的,同时数据的维护是在数据库内部执行,而不需要应用程序来维护,更不需要人工干预。
下面通过具体的实例就触发器实现数据库特殊的计算要求和数据联动等复杂的业务逻辑进行探讨。
触发器是用户定义在数据表上的一种被事件驱动的由DBMS调用执行的特殊存储过程[1]。触发器是建立在一个基本表或视图上的特殊类型的存储过程,当这个表发生了更新操作即Insert、Update或Delete时,会自动被激活执行而不需要人工干预,可以处理各种复杂的业务规则。触发器是维护数据库完整性的另一有力工具。
inserted表和deleted表是两个系统临时表。这两个表的结构与触发器作用的表的结构相同,且由系统自动创建和撤销,只能在触发器中引用这2个表。In⁃serted表存放insert操作的记录和update更新后的记录,deleted表存放delete操作删除的记录以及update更新前的记录。
For|After:指定DML触发器仅在触发SQL语句中指定的所有操作都已成功执行时才被触发[2]。也就是说after触发器是在触发命令成功执行之后才激活触发器,完成触发器中规定的操作,所以,一旦由于一些特殊原因造成更新的记录不符合要求时,需要在触发器中回滚Rollback该操作,避免数据出现错误。After触发器要求只执行插入、更新、删除中任一操作之后激活触发器执行[3]。
为了简单起见,假设该数据库仅包含2个表:商品库存表和商品销售表,表结构分别如下:
库存表 kc(spname(商品名称),kcprice(库存单价),kcqty(库存数量),kctotal(库存金额)),spname为主键。业务规则为:kctotal=kcprice×kcqty。
销售表 xs(spname(商品名称),buyer(购货商),xsprice(销售单价),xsqty(销售数量),xstotal(销售金额)),spname为主键。业务规则为:xstotal=xsprice×xsqty。
这2个表之间数据存在这样的关系:每当向销售表插入记录时,库存表中相应商品的库存数量要减去销售数量,库存金额也要根据该表的业务规则重新计算。
为库存表创建一个Insert操作的After触发器,每当向库存表插入记录时触发该触发器。每当插入一条新记录,保证插入的数据中,库存金额始终等于库存数量和库存单价的乘积。
创建触发器的代码如下:
上述四条命令,有的符合业务规则,有的不符合。查看商品库存表,select*from kc,结果如表1所示。从表中数据可以看出,无论输入数据时,库存金额kctotal是否符合业务规则都没有关系,因为有了这个触发器,保证了每条记录的库存金额始终是符合业务规则的。
表1 库存表KC
为销售表创建一个Insert触发器,每当向销售表xs插入记录时,触发此触发器。该触发器完成如下工作:检查销售的商品是否在库存表kc中存在,有以下三种情况:1)kc中不存在此商品;2)kc中有此商品,但是库存为零;3)kc中存在此商品,且库存数量大于零,则更新销售表xs中的销售金额,维护该表的业务规则,同时自动减少kc中对应商品的库存数量kcqty,实现数据联动,并更新库存表kc中的库存金额kcto⁃tal,维护库存表的业务规则。其中前2种情况需要提示相应的信息,并且回滚该insert操作,避免出现库存表中不存在或库存为零的商品却可以销售的错误情况,从而维护数据的完整性。该触发器代码如下:
此商品在库存表中存在,且库存大于零,可以销售,命令中的销售金额不符合业务规则,但是因为建立了此触发器,销售金额会始终符合业务规则,同时库存表中的相应商品的库存数量和库存金额也随着更新了,从而实现了两个表中数据的联动。
Insert into xs values('FFER','BUYER2',10,270,2700)
此商品在库存表中不存在,所以不能销售,回滚了
此条命令。
Insert into xs values('DDD','BUYER3',10,410,4000)
此商品在库存中存在,但是库存小于等于零,即缺货,所以不能销售,回滚了此条命令。
查询销售表,Select*from xs,如表2所示。可以看出,上述三条Insert语句只有第一条成功插入,且销售金额符合业务规则。
查询商品库存表,Select*from kc,如表3所示。可以看出,商品名称为“AAA”的商品的库存数量和库存金额被自动更新了。
表2 商品销售表xs
表3 商品库存表kc
观察表2和表3中数据可以看出两个表中的数据是一致的,每当向销售表中插入一条新记录,该表上的销售金额始终符合业务规则,同时库存表上该商品的库存数量和库存金额随着更新,实现了2个表之间的数据联动。
由此可以得出:当表中某字段的数据是通过计算得出时,建立相应触发器可以保证该字段数据的正确性;当表之间数据有关联时,即一个表中的数据变动会引起关联表中数据的联动,这时建立一个触发器是明智的,因为人工维护这样的数据是很麻烦且容易出错的,随着数据量的增加,人工是无法完成的,但是触发器就可以很好地胜任此工作,而且不会出错。由此可以看出触发器在数据库完整性的维护方面起到了不可替代的作用。
当然上诉两个触发器并不完美,因为插入的记录必须是新的记录,即和表中数据没有重复(因为商品名称是主键),这和现实是有冲突的。例如:同一种商品需要经常进货,同一种商品也需要多次销售,在这种情况下,上述2个触发器就不能完成这样的要求了,所以触发器要做相应改动,例如改成Instead of触发器就可以很好完成上述要求,从而保证数据的完整性。由于篇幅有限就不在此做探讨了。
综上所述,可以看出触发器在维护数据库完整性性方面有其特殊的贡献,数据库中数据的正确性、有效性、一致性和相容性始终是数据库的宗旨,没有正确的数据就没有正确的信息,所以当数据库中数据有特殊的业务规则及复杂的业务逻辑例如数据联动时,设计相应的触发器是数据库数据正确性的有力保证。
[1]李虎军,金泉,邢旺,张政.探析SQL Server触发器与完整性约束的区别[J].电脑知识与技术,2016(12):10-12.
[2]马建红,李占波.数据库原理及应用(SQL SQL Server 2008)[M].北京:清华大学出版社,2011:229.
[3]陈舒心.触发器在数据库设计中的应用[J].广东教育,2016(4):110-111,119.2016(23):10-12.