更新时间:2023-06-14 10:32
触发程序(trigger)是一种特殊型态的预存程序,当您使用INSERT、UPDATE或DELETE命令来修改资料列时,Microsoft SQL Server会自动执行您所定义的触发程序。
触发程序(trigger) 是一种特殊的预存程序,执行特定的陈述式(UPDATE、INSERT 或 DELETE)就可以启动触发程序。触发程序与其他预存程序相同,可以是由简单,亦或是复杂的 T-SQL 陈述式组成;至于与其他预存程序不同的地方,则在于当指定的资料被修改,触发程序即自动执行,无法依名称以手动执行。触发程序执行时,称为触动(fire)。触发程序虽建立在现有的资料库资料表中,但它可以存取其他资料库的资料表和物件。触发程序不能建立在临时的资料表或临时的系统资料表上,只能建立在使用者自订资料表或自订的检视表中。执行触发程序所在的资料表或检视表,称为触发程序资料表(trigger table)。
触发程序有五种类型:UPDATE、INSERT、DELETE、INSTEAD OF 和 AFTER。有了触发程序,只要您对该表格更新、插入或删除时,就会触动对应的 UPDATE、INSERT 或 DELETE 触发程序。INSTEAD OF 和 AFTER 是 SQL 2000 新增的两项触发程序,Instead of的原义是“取代”,INSTEAD OF触发程序会取代插入、更新和删除操作而执行。AFTER 触发程序会在触发动作之后再触动,可视为控制触发程序启动时间的机制。
对资料的更新、插入及删除被视为资料修改事件。您可以设计当一项或多项修改事件产生时,即触动触发程序。例如,当执行 UPDATE 或 INSERT 陈述式时即触动触发程序。这种类型的触发程序称为 UPDATE/INSERT 触发程序。您也可以建立任何一项修改事件产生时,执行相对的 UPDATE/INSERT/DELETE 触发程序。
下面是关于触发程序的一些其他规定:
触发程序只在触发它的陈述式完成后执行。举例来说,如果 UPDATE 陈述式成功,UPDATE 触发程序才会被触动。
如果陈述式在资料表中执行违反条件约束或引起错误,触发程序不会触动。
触发程序视为单一交易中的一部份,因此可以由原触发程序复原交易,如果在交易过程中侦测到严重的错误(如使用者中断连线),则会自动复原整个交易。
当触发程序触动,若产生任何结果,就会如预存程序一样,将结果传回其呼叫的应用程式。一般来说,INSERT、UPDATE 或 DELETE 的陈述式(触动触发程序的陈述式)不会将结果传回;结果通常由 SELECT 查询传回。因此,为了避免触发程序传回结果给应用程式,请勿在触发程序定义中引入 SELECT 陈述式或指派变数。如果希望从触发程序中传回结果,在允许修改触发资料表的每个应用程式中都必须撰写特殊的程式,才能使应用程式收到传回的资料并进行正确的处理。
如果您必须在触发程序中指派变数,则可在触发程序的起始位置使用 SET NOCOUNT ON 陈述式以防止传回任何结果资料列。SET NOCOUNT 陈述式指定是否传回查询或受陈述式影响的资料列数目的资讯(例如,影响 23 个资料列)。SET NOCOUNT 的预设值是设在 OFF,也就是说会传回受影响列的讯息。该设定并不影响 SELECT 陈述式实际结果的传回,只传回计数。
背景资料
使用触发程序程序的好处是SQL Server会使用触发程序以自动执行该触发程序所定义的命令,这使得数据库功能性更为强大。因此只要您事先定义触发程序,您不需要担心数据库客户端(这包含了使用者或应用程序)是否了解所有的资料依存性和商业规则。
举例来说,一位业务员已经规划了一个订单总计等于或大于$10,000时,就必须要进行信用检查的规则。假如CreditApproved是指Customer资料表内的一个资料行,而现在有一笔订单的相关资料要新增至Order资料表中,此时您无法使用CHECK条件约束来执行此规则。但是更令人烦恼的是您要在数据库客户端强制这些规则更为困难,于是触发程序就可以提供在数据库本身进行建置此规则的机制。
触发程序也可以用于避免客户端变更数据库规则。继续前一个范例,假如将商业规则更改为金额大于或等于$15,000时才需要信用验证时,这个新的规则可以在数据库层级建置,而您不需要检查和更新所有客户端的应用程序。
触发程序最典型的使用方式是-商业规则无法使用资料表条件约束强制建置时,就使用触发程序。触发程序很早就已经需要串联参考完整性(cascading referential integrity)的功能,但是直到SQL Server 2000这个版本才支持。然而,现在我们可以在资料表层级使用触发程序建置串联参考完整性,就像刚才的范例一样。大多数的商业规则会涉及多个资料表-例如计算总和需要使用到其它的资料表,这通常藉由触发程序会比较容易建置。
提示
纵使触发程序的执行效能并不是问题的重点所在(当它和资料指针一起使用时),您应该尽可能的使用较低阶的方式建置规则。假如您的商业规则可以利用CHECK条件约束建置时,您就不应该使用触发程序;而如果您可以使用UNIQUE条件约束时,您就不应该使用CHECK条件约束。
AFTER触发程序
SQL Server 2000支持了二种不同的触发程序型态:AFTER触发程序和INSTEAD OF触发程序。触发的情况分别如下:AFTER触发程序将会在其所定义的命令执行后被触发;INSTEAD OF触发程序将会代替其所定义的命令被触发。
您可以针对INSERT、UPDATE和DELETE命令建立AFTER触发程序。AFTER触发程序只能在资料表上建立,而不能在检视表上建立。但是您可以针对这三个命令分别建立多个触发程序,相对地,单一的触发程序也可以套用这三个命令的任意组合。
提示
假如您针对单一个命令建立多个触发程序时,您可以使用系统预存程序sp_settriggerorder来设定该命令执行时的第一个和最后一个触发程序。
AFTER触发程序会在所有的条件约束被处理之后再触发,假如有违反条件约束的情况发生时,该AFTER触发程序将不会被触发。
举例来说,假如在资料表中试图新增资料列而导致违反PRIMARY KEY条件约束时,该INSERT陈述式会在呼叫触发程序之前就发生执行失败。
INSTEAD OF触发程序
INSTEAD OF触发程序会取代其所定义的命令被触发。就像AFTER触发程序一样,您可以在INSERT、UPDATE或DELETE命令中定义INSTEAD OF触发程序。单一的触发程序可以套用多重命令的任意组合。
与AFTER触发程序不同的是,您可以针对资料表和检视表来建立INSTEAD OF触发程序,但是在资料表或检视表上的每一个动作,您只能建立单一个INSTEAD OF触发程序。
INSTEAD OF触发程序不兼容于串联参考完整性。INSTEAD OF DELETE与INSTEAD OF UPDATE触发程序不能定义于以DELETE或UPDATE动作定义外部索引键的资料表。
因为INSTEAD OF触发程序可以宣告在检视表中,所以它们非常地适用于建置检视表的功能性。举例来说,针对一个包含有GROUP BY子句的检视表来说,SQL Server会防止使用INSERT陈述式,但是却允许您针对该检视表定义一个INSTEAD OF INSERT触发程序。您可以使用该触发程序以将资料列插入定义检视表的底层资料表中。
BEFORE触发程序
就本质上而言,是没有BEFORE触发程序的。但是INSTEAD OF触发程序可以代替其所定义的命令执行。如果没有INSTEAD OF触发程序存在,则该命令就会真的执行。
举例来说,假如您想要在INSERT之前检查某些条件时,您可以宣告一个INSTEAD OF INSERT触发程序。该INSTEAD OF触发程序将执行此检查,然后在资料表中执行INSERT。该INSERT陈述式将会正常地执行,而不需要递归地呼叫INSTEAD OF触发程序。
SQL Server使用触发程序来处理一些条件约束。您无法使用触发程序CREATE、ALTER或DROP数据库、您无法使用触发程序将数据库或交易记录档案进行还原、并且您无法使用触发程序进行更改SQL Server设定的操作(您可以参考“SQL Server线上丛书”所提供的完整说明)。
假如您在触发程序中更改数据库选项时,您所更改的选项只会在触发程序执行期间有效,但是在触发程序执行完毕之后,您所更改的值将会恢复到原来的值。
理论上,您可以使用RETURN陈述式自触发程序中传回一个值,但是您不应该依赖客户端应用程序来探知该触发程序是否存在或该触发程序作了什么。RAISERROR命令提供了一个比较好的技术,因为大多数的应用程序的设计会掌控这些错误。
CREATE TRIGGER命令
使用CREATE TRIGGER命令
就像其它的数据库对象一样,您可以使用CREATE陈述式的形式建立一个触发程序。CREATE陈述式的基本语法为:
CREATE TRIGGER trigger_name
ON table_or_view
trigger_type command_list
AS
SQL_statements
唯一性的规则
其中trigger_name必须要遵守唯一性的规则,假如trigger_type是INSTEAD OF时,table_or_view可以是检视表名称,因为您只可以在检视表中定义INSTEAD OF触发程序。触发程序不能建立在暂存资料表或系统资料表中,但是它们可以引用暂存资料表。
trigger_type关键词只能是AFTER、FOR或INSTEAD OF其中之一;command_list可以联合使用任何INSERT、UPDATE或DELETE命令,假如您要使用一个以上的命令时,您可以使用逗号“,”将这些命令区隔开来。
提示
早期的SQL Server版本仅支持AFTER触发程序和trigger_type FOR语法,此语法在SQL Server 2000中也有支持,但是它与AFTER所表示的意思是相同的。
您可将触发程序储存至数据库中。在储存全新或更新的触发程序时,触发程序会加入 [资料表] 资料夹中。
若要储存触发程序
在 [档案] 菜单中,按一下 [储存 <触发程序名称>]。
如果更新现存触发程序,则会出现消息框,提示您确认是否要进行储存动作。请选择 [是]。
显示于服务器总管内 [资料表] 资料夹中的已储存触发程序,位于其所属的资料表下。
您可开启触发程序,来检视或编辑数据库中现存触发程序的文字。触发程序在 Transact-SQL for Microsoft ® SQL Server™ 数据库或 PL/SQL for Oracle 数据库中编写指令码。
在服务器总管中,触发程序与数据库资料表资料行是以触发程序图标来区分。
若要开启触发程序
在服务器总管内,展开 [资料表] 资料夹。
将准备开启的触发程序所在的资料表展开。
在准备开启的触发程序名称上按一下鼠标右键,并于快速键菜单上选择 [编辑触发程序]。
- 或 -
连按两下您要开启的触发程序名称。
触发程序在可用以编辑 SQL 陈述式的原始程序代码编辑器中开启。
您可删除数据库中不再需要,或者会执行不必要动作的触发程序。例如,如果您使用数据库图表来设计数据库,则会使用关联性来实行参考完整性,而非使用触发程序。如果触发程序重复了数据库图表内的关联性,则应该删除触发程序或者关联性。如需删除关联性的详细信息,请参阅删除关联性。
若要删除触发程序
在服务器总管内,展开 [资料表] 资料夹。
将准备删除的触发程序所在的资料表展开。
在准备删除的触发程序上,按一下鼠标右键,并于快速键菜单上选择 [删除]。
会出现讯息提示您确认是否删除。请选择 [是]。
触发程序自数据库与服务器总管中删除。
触发程序适用于下列方式:
触发程序是自动的。触发程序在资料表内的资料经过修改 (例如手动输入或应用程序动作) 后,会立即激活。
触发程序可透过数据库的关联资料表串联 (Cascade) 变更。例如,您可以在 titles 资料表的 title_id 资料行中,写入某个删除触发程序,以便删除其它资料表中相符的资料列。触发程序使用 title_id 资料行做为唯一键,以便从 titleauthor、sales 和 roysched 资料表中找出符合的资料列。
注意在 SQL Server 2000 环境下,也可以透过关联资料表串联变更;方法是在外部索引键条件约束中设定 CASCADE UPDATE 或 DELETE (或同时设定两种) 条件约束。
触发程序可实行检查条件约束中所定义更为复杂的限制。触发程序与检查条件约束不同,前者可以参考其它资料表内的资料行。例如,触发程序可以将尝试套用折扣的更新项目 (储存于 discounts 资料表) 复原为书籍 (储存于 titles 资料表),其价格会低于 $10。
如需使用条件约束的详细信息,请参阅下列主题:
至 请参阅
建立新触发程序 建立触发程序
开启现存触发程序 开启触发程序
将触发程序储存至您的项目中 储存触发程序
使用 INSTEAD OF 触发程序 在检视中使用 INSTEAD OF 触发程序
删除预存触发程序 删除触发程序
如需详细信息以及触发程序的范例,请参阅您的数据库服务器文件。如果您使用 Microsoft SQL Server,请参阅《SQL Server 线上丛书》的部份。
触发程序和条件约束相同,可用来维持资料的完整性和商业规则,但是触发程序不能取代条件约束。例如,您不需要建立触发程序来检查资料表中主索引键中的某个值是否存在,才能决定这个值是否能被插入到另一个资料表中的相对应资料行(外部索引键条件约束在这种情况下才是一个较好的选择)。您应当建立一个触发程序来启动资料库中所有相关资料表的串联变更,例如,您可能在 pubs 资料库中titles这个资料表中的title_id资料行上建立 DELETE 触发程序,当您在titles栏位中删除一笔资料时,在sales、roysched和titleauthor资料表中对应资料的资料行也会被删除(在接下来的章节我们将看到如何建立该 DELETE 触发程序)。
您还可以利用触发程序执行比 CHECK 条件约束更复杂的资料检测(CHECK 条件约束在 第十六章 有详细讨论)。由于触发程序可以引用其他资料表中的资料行,因此才可能执行复杂的资料检测;反之,CHECK 条件约束只限于在其所定义的资料表上执行。
您还可以建立多重触发程序,当资料修改时即触动所有触发程序。(请记住,如果在资料表或检视表中为一个事件定义多重触发程序,每个触发程序都必须有一个自己的名称)。
或者您可以建立单一触发程序,在资料修改时即被触动。也就是每一次当被定义的事件发生,触发程序就被触动一次。因此,若是在资料表上定义 INSERT、UPDATE 和 DELETE 的触发程序,每次定义的事件产生时,触发程序就会触动。
在建立触发程序时,SQL Server 会为触发程序建立两个暂时资料表,您可以参考这两个资料表,用 T-SQL 撰写触发程序定义。这些资料表固定储存在与触发程序一起的记忆体中,每个触发程序只能存取自己的暂时资料表,暂时资料表即为触发程序所在资料表的一个副本。您可以使用这些资料表比较资料修改前后状态。下一节将列举这些特殊资料表(称为deleted和inserted资料表)。