zoukankan      html  css  js  c++  java
  • 数据库触发器

    SQL触发器,是一种特殊类型的存储过程,不由用户直接调用。它在指定的表中的数据发生变化时自动生效。唤醒调用触发器以响应 INSERT、UPDATE 或 DELETE 语句。他可以查询其它表,并可以包含复杂的Transact-SQL语句。将触发器和触发它的语句作为可在触发器内回滚的单个事务对待。如果检测到严重错误(例如,磁盘空间不足),则整个事务即自动回滚。常常用于强制业务规则和数据完整性

    • DML( 数据操纵语言 Data Manipulation Language)触发器:是指触发器在数据库中发生DML事件时启用。DML事件即指在表或视图中修改数据的insert、update、delete语句。

      a、在SQL SERVER 2008中,DML触发器的实现使用两个逻辑表DELETED和INSERTED。这两个表是建立在数据库服务器的内存中,我们只有只读的权限。DELETED和INSERED表的结构和触发器所在的数据表的结构是一样的。当触发器执行完成后,它们也就会被自动删除:INSERED表用于存放你在操件insert、update、delete语句后,更新的记录。比如你插入一条数据,那么就会把这条记录插入到INSERTED表:DELETED表用于存放你在操作 insert、update、delete语句前,你创建触发器表中数据库。

      b、触发器可通过数据库中的相关表实现级联更改,可以强制比用CHECK约束定义的约束更为复杂的约束。与 CHECK 约束不同,触发器可以引用其它表中的列,例如触发器可以使用另一个表中的 SELECT 比较插入或更新的数据,以及执行其它操作。触发器也可以根据数据修改前后的表状态,再行采取对策。一个表中的多个同类触发器(INSERT、UPDATE 或 DELETE)允许采取多个不同的对策以响应同一个修改语句。

      c、与此同时,虽然触发器功能强大,轻松可靠地实现许多复杂的功能,为什么又要慎用?过多触发器会造成数据库及应用程序的维护困难,同时对触发器过分的依赖,势必影响数据库的结构,同时增加了维护的复杂程序。

    • DDL(数据定义语言 Data Definition Language)触发器:是指当服务器或数据库中发生(DDL事件时启用。DDL事件即指在表或索引中的create、alter、drop语句也。

    • 登陆触发器:是指当用户登录SQL SERVER实例建立会话时触发。

    2优点

    编辑

    触发器可通过数据库中的相关表实现级联更改;通过级联引用完整性约束可以更有效地执行这些更改。

    触发器可以强制比用 CHECK 约束定义的约束更为复杂的约束。

    与 CHECK 约束不同,触发器可以引用其它表中的列。例如,触发器可以使用另一个表中的 SELECT 比较插入或更新的数据,以及执行其它操作,如修改数据或显示用户定义错误信息。

    触发器也可以评估数据修改前后的表状态,并根据其差异采取对策。

    比较触发器与约束

    约束和触发器在特殊情况下各有优势。触发器的主要好处在于它们可以包含使用 Transact-SQL 代码的复杂处理逻辑。因此,触发器可以支持约束的所有功能;但它在所给出的功能上并不总是最好的方法。

    实体完整性总应在最低级别上通过索引进行强制,这些索引或是 PRIMARY KEY 和 UNIQUE 约束的一部分,或是在约束之外独立创建的。假设功能可以满足应用程序的功能需求,域完整性应通过 CHECK 约束进行强制,而引用完整性 (RI) 则应通过 FOREIGN KEY 约束进行强制。

    在约束所支持的功能无法满足应用程序的功能要求时,触发器就极为有用。例如:

    除非 REFERENCES 子句定义了级联引用操作,否则 FOREIGN KEY 约束只能以与另一列中的值完全匹配的值来验证列值。

    CHECK 约束只能根据逻辑表达式或同一表中的另一列来验证列值。如果应用程序要求根据另一个表中的列验证列值,则必须使用触发器。

    约束只能通过标准的系统错误信息传递错误信息。如果应用程序要求使用(或能从中获益)自定义信息和较为复杂的错误处理,则必须使用触发器。

    触发器可通过数据库中的相关表实现级联更改;不过,通过级联引用完整性约束可以更有效地执行这些更改。

    触发器可以禁止或回滚违反引用完整性的更改,从而取消所尝试的数据修改。当更改外键且新值与主键不匹配时,此类触发器就可能发生作用。例如,可以在 titleauthor.title_id 上创建一个插入触发器,使它在新值与 titles.title_id 中的某个值不匹配时回滚一个插入。不过,通常使用 FOREIGN KEY 来达到这个目的。

    如果触发器表上存在约束,则在 INSTEAD OF触发器执行后但在 AFTER触发器执行前检查这些约束。如果约束破坏,则回滚INSTEAD OF触发器操作并且不执行 AFTER触发器。

    语法

    编辑

    CREATE TRIGGER trigger_name

    ON { table|view }

    [ WITH ENCRYPTION ]

    {

    { { FOR|AFTER|INSTEAD OF } { [ INSERT ] [ DELETE ] [ UPDATE ] }

    [ WITH APPEND ]

    [ NOT FOR REPLICATION ]

    AS

    [ { IF UPDATE ( column )

    [ { AND|OR } UPDATE ( column ) ]

    [ ...n ]

    |IF ( COLUMNS_UPDATED ( ) updated_bitmask )

    column_bitmask [ ...n ]

    } ]

    sql_statement [ ...n ]

    }

    }

    参数

    trigger_name

    是触发器的名称。触发器名称必须符合标识符规则,并且在数据库中必须唯一。可以选择是否指定触发器所有者名称。

    Table|view

    是在其上执行触发器的表或视图,有时称为触发器表或触发器视图。可以选择是否指定表或视图的所有者名称。

    WITH ENCRYPTION

    加密 syscomments 表中包含 CREATE TRIGGER 语句文本的条目。使用 WITH ENCRYPTION 可防止触发器作为 SQL Server 复制的一部分发布。

    AFTER

    指定触发器只有在触发 SQL 语句中指定的所有操作都已成功执行后才激发。所有的引用级联操作和约束检查也必须成功完成后,才能执行此触发器。

    如果仅指定 FOR 关键字,则 AFTER 是默认设置。

    不能在视图上定义 AFTER 触发器。

    INSTEAD OF

    指定执行触发器而不是执行触发 SQL 语句,从而替代触发语句的操作。

    在表或视图上,每个 INSERT、UPDATE 或 DELETE 语句最多可以定义一个 INSTEAD OF 触发器。然而,可以在每个具有 INSTEAD OF触发器的视图上定义视图。

    INSTEAD OF触发器不能在 WITH CHECK OPTION 的可更新视图上定义。如果向指定了 WITH CHECK OPTION 选项的可更新视图添加 INSTEAD OF触发器,SQL Server产生一个错误。用户必须用 ALTER VIEW 删除该选项后才能定义 INSTEAD OF 触发器。

    { [DELETE] [,] [INSERT] [,] [UPDATE] }

    是指定在表或视图上执行哪些数据修改语句时激活触发器的关键字。必须至少指定一个选项。在触发器定义中允许使用以任意顺序组合的这些关键字。如果指定的选项多于一个,需用逗号分隔这些选项。

    对于 INSTEAD OF触发器,不允许在具有 ON DELETE 级联操作引用关系的表上使用 DELETE 选项。同样,也不允许在具有 ON UPDATE 级联操作引用关系的表上使用 UPDATE 选项。

    WITH APPEND

    指定应该添加现有类型的其它触发器。只有当兼容级别是 65 或更低时,才需要使用该可选子句。如果兼容级别是 70 或更高,则不必使用 WITH APPEND 子句添加现有类型的其它触发器(这是兼容级别设置为 70 或更高的 CREATE TRIGGER 的默认行为)。有关更多信息,请参见 sp_dbcmptlevel。

    WITH APPEND 不能与 INSTEAD OF触发器一起使用,或者,如果显式声明 AFTER 触发器,也不能使用该子句。只有当出于向后兼容而指定 FOR 时(没有 INSTEAD OF 或 AFTER),才能使用 WITH APPEND。以后的版本不支持 WITH APPEND 和 FOR(被解释为 AFTER)。

    NOT FOR REPLICATION

    表示当复制进程更改触发器所涉及的表时,不应执行该触发器。

    AS

    是触发器要执行的操作。

    sql_statement

    是触发器的条件和操作。触发器条件指定其它准则,以确定 DELETE、INSERT 或 UPDATE 语句是否导致执行触发器操作。

    当尝试 DELETE、INSERT 或 UPDATE 操作时,Transact-SQL语句中指定的触发器操作生效。

    触发器可以包含任意数量和种类的 Transact-SQL 语句。触发器旨在根据数据修改语句检查或更改数据;它不应数据返回给用户。触发器中的 Transact-SQL 语句常常包含控制流语言。CREATE TRIGGER 语句中使用几个特殊的表:

    * deleted 和 inserted 是逻辑(概念)表。这些表在结构上类似于定义触发器的表(也就是在其中尝试用户操作的表);这些表用于保存用户操作可能更改的行的旧值或新值。例如,若要检索 deleted 表中的所有值,请使用:

    SELECT *

    FROM deleted

    * 如果兼容级别等于 70,那么在 DELETE、INSERT 或 UPDATE触发器中,SQL Server不允许引用 inserted 和 deleted 表中的 text、ntext 或 image 列。不能访问 inserted 和 deleted 表中的 text、ntext 和 image 值。若要在 INSERT 或 UPDATE触发器中检索新值,请inserted 表与原始更新表联接。当兼容级别是 65 或更低时,对 inserted 或 deleted 表中允许空值的text、ntext 或 image 列,返回空值;如果这些列不可为空,则返回零长度字符串。

    当兼容级别是 80 或更高时,SQL Server 允许在表或视图上通过 INSTEAD OF触发器更新 text、ntext 或 image 列。

    n

    是表示触发器中可以包含多条 Transact-SQL 语句的占位符。对于 IF UPDATE (column) 语句,可以通过重复 UPDATE (column) 子句包含多列。

    IF UPDATE (column)

    测试在指定的列上进行的 INSERT 或 UPDATE 操作,不能用于 DELETE 操作。可以指定多列。因为在 ON 子句中指定了表名,所以在 IF UPDATE 子句中的列名前不要包含表名。若要测试在多个列上进行的 INSERT 或 UPDATE 操作,请在第一个操作后指定单独的 UPDATE(column) 子句。在 INSERT 操作中 IF UPDATE返回 TRUE 值,因为这些列插入了显式值或隐性 (NULL) 值。

    说明 IF UPDATE (column) 子句的功能等同于 IF、IF...ELSE 或 WHILE 语句,并且可以使用 BEGIN...END 语句块。有关更多信息,请参见控制流语言。

    可以在触发器主体中的任意位置使用 UPDATE (column)。

    column

    是要测试 INSERT 或 UPDATE 操作的列名。该列可以是 SQL Server 支持的任何数据类型。但是,计算列不能用于该环境中。有关更多信息,请参见数据类型。

    IF (COLUMNS_UPDATED())

    测试是否插入或更新了提及的列,仅用于 INSERT 或 UPDATE触发器中。COLUMNS_UPDATED 返回 varbinary 位模式,表示插入或更新了表中的哪些列。

    COLUMNS_UPDATED 函数以从左到右的顺序返回位,最左边的为最不重要的位。最左边的位表示表中的第一列;向右的下一位表示第二列,依此类推。如果在表上创建的触发器包含 8 列以上,则 COLUMNS_UPDATED 返回多个字节,最左边的为最不重要的字节。在 INSERT 操作中 COLUMNS_UPDATED对所有列返回 。

    可以在触发器主体中的任意位置使用 COLUMNS_UPDATED。

    bitwise_operator

    是用于比较运算的位运算符。

    updated_bitmask

    是整型位掩码,表示实际更新或插入的列。例如,表 t1 包含列 C1、C2、C3、C4 和 C5。假定表 t1 上有 UPDATE触发器,若要检查列 C2、C3 和 C4 是否都有更新,指定值 14;若要检查是否只有列 C2 有更新,指定值 2。

    comparison_operator

    比较运算符。使用等号 (=) 检查 updated_bitmask 中指定的所有列是否都实际进行了更新。使用大于号 (>) 检查 updated_bitmask 中指定的任一列或某些列是否已更新。

    column_bitmask

    是要检查的列的整型位掩码,用来检查是否已更新或插入了这些列。

    注释

    触发器常常用于强制业务规则和数据完整性。SQL Server 通过表创建语句(ALTER TABLE 和 CREATE TABLE)提供声明引用完整性(DRI);但是 DRI 不提供数据库间的引用完整性。若要强制引用完整性(有关表的主键和外键之间关系的规则),请使用主键和外键约束(ALTER TABLE 和 CREATE TABLE 的 PRIMARY KEY 和 FOREIGN KEY关键字)。如果触发器表存在约束,则在 INSTEAD OF触发器执行之后和 AFTER触发器执行之前检查这些约束。如果违反了约束,则回滚INSTEAD OF触发器操作且不执行(激发)AFTER触发器。

    可用 sp_settriggerorder 指定表上第一个和最后一个执行的 AFTER触发器。在表上只能为每个 INSERT、UPDATE 和 DELETE 操作指定一个第一个执行和一个最后一个执行的 AFTER触发器。如果同一表上还有其它 AFTER触发器,则这些触发器以随机顺序执行。

    如果 ALTER TRIGGER 语句更改了第一个或最后一个触发器,则除去已修改触发器上设置的第一个或最后一个特性,而且必须用 sp_settriggerorder 重置排序值。

    只有当触发 SQL 语句(包括所有与更新或删除的对象关联的引用级联操作和约束检查)成功执行后,AFTER触发器才会执行。AFTER触发器检查触发语句的运行效果,以及所有由触发语句引起的 UPDATE 和 DELETE 引用级联操作的效果。

    触发器限制

    CREATE TRIGGER 必须是批处理中的第一条语句,并且只能应用到一个表中。

    触发器只能在当前的数据库中创建,不过触发器可以引用当前数据库的外部对象。

    如果指定触发器所有者名称以限定触发器,请以相同的方式限定表名。

    在同一条 CREATE TRIGGER 语句中,可以为多种用户操作(如 INSERT 和 UPDATE)定义相同的触发器操作。

    如果一个表的外键在 DELETE/UPDATE 操作上定义了级联,则不能在该表上定义 INSTEAD OF DELETE/UPDATE 触发器。

    在触发器内可以指定任意的 SET 语句。所选择的 SET 选项在触发器执行期间有效,并在触发器执行完后恢复到以前的设置。

    与使用存储过程一样,当触发器激发时,向调用应用程序返回结果。若要避免由于触发器激发而向应用程序返回结果,请不要包含返回结果的 SELECT 语句,也不要包含在触发器中进行变量赋值的语句。包含向用户返回结果的 SELECT 语句或进行变量赋值的语句的触发器需要特殊处理;这些返回的结果必须写入允许修改触发器表的每个应用程序中。如果必须在触发器中进行变量赋值,则应该在触发器的开头使用 SET NOCOUNT 语句以避免返回任何结果集。

    DELETE触发器不能捕获 TRUNCATE TABLE 语句。尽管 TRUNCATE TABLE 语句实际上是没有 WHERE 子句的 DELETE(它删除所有行),但它是无日志记录的,因而不能执行触发器。因为 TRUNCATE TABLE 语句的权限默认授予表所有者且不可转让,所以只有表所有者才需要考虑无意中用 TRUNCATE TABLE 语句规避 DELETE触发器的问题。

    无论有日志记录还是无日志记录,WRITETEXT 语句都不激活触发器。

    触发器中不允许以下 Transact-SQL 语句:

    ALTER DATABASE CREATE DATABASE DISK INIT

    DISK RESIZE DROP DATABASE LOAD DATABASE

    LOAD LOG RECONFIGURE RESTORE DATABASE

    RESTORE LOG

    说明 由于 SQL Server 不支持系统表中的用户定义触发器,因此建议不要在系统表中创建用户定义触发器。

    多个触发器

    SQL Server 允许为每个数据修改事件(DELETE、INSERT 或 UPDATE)创建多个触发器。例如,如果对已有 UPDATE触发器的表执行 CREATE TRIGGER FOR UPDATE,则创建另一个更新触发器。在早期版本中,在每个表上,每个数据修改事件(INSERT、UPDATE 或 DELETE)只允许有一个触发器。

    说明 如果触发器名称不同,则 CREATE TRIGGER(兼容级别为 70)的默认行为是在现有的触发器中添加其它触发器。如果触发器名称相同,则 SQL Server 返回一条错误信息。但是,如果兼容级别等于或小于 65,则使用 CREATE TRIGGER 语句创建的新触发器替换同一类型的任何现有触发器,即使触发器名称不同。有关更多信息,请参见 sp_dbcmptlevel。

    递归触发器

    当在 sp_dboption 中启用 recursive triggers 设置时,SQL Server 还允许触发器的递归调用。

    递归触发器允许发生两种类型的递归:

    * 间接递归

    * 直接递归

    使用间接递归时,应用程序更新表 T1,从而激发触发器TR1,该触发器更新表 T2。在这种情况下,触发器T2激发并更新 T1。

    使用直接递归时,应用程序更新表 T1,从而激发触发器TR1,该触发器更新表 T1。由于表 T1 被更新,触发器TR1 再次激发,依此类推。

    下例既使用了间接触发器递归,又使用了直接触发器递归。假定在表 T1 中定义了两个更新触发器TR1 和 TR2。触发器 TR1 递归地更新表 T1。UPDATE 语句使 TR1 和 TR2 各执行一次。而 TR1 的执行触发 TR1(递归)和 TR2 的执行。给定触发器的 inserted 和 deleted 表只包含与唤醒调用触发器的 UPDATE 语句相对应的行。

    说明 只有启用 sp_dboption 的 recursive triggers 设置,才会发生上述行为。对于为给定事件定义的多个触发器,并没有确定的执行顺序。每个触发器都应是自包含的。

    禁用 recursive triggers 设置只能禁止直接递归。若要也禁用间接递归,请使用 sp_configurenested triggers 服务器选项设置为 0。

    如果任一触发器执行了 ROLLBACK TRANSACTION 语句,则无论嵌套级是多少,都不会进一步执行其它触发器。

    嵌套触发器

    触发器最多可以嵌套 32 层。如果一个触发器更改了包含另一个触发器的表,则第二个触发器激活,然后该触发器可以再调用第三个触发器,依此类推。如果链中任意一个触发器引发了无限循环,则会超出嵌套级限制,从而导致取消触发器。若要禁用嵌套触发器,请用 sp_configurenested triggers 选项设置为 0(关闭)。默认配置允许嵌套触发器。如果嵌套触发器是关闭的,则也禁用递归触发器,与 sp_dboption 的 recursive triggers 设置无关。

    延迟名称解析

    SQL Server 允许 Transact-SQL存储过程、触发器和批处理引用编译时不存在的表。这种能力称为延迟名称解析。但是,如果 Transact-SQL存储过程、触发器或批处理引用在存储过程或触发器中定义的表,则只有当兼容级别设置(通过执行 sp_dbcmptlevel 设置)等于 65 时,才会在创建时发出警告。如果使用批处理,则在编译时发出警告。如果引用的表不存在,在运行时返回错误信息。有关更多信息,请参见延迟名称解析和编译。

    权限

    CREATE TRIGGER 权限默认授予定义触发器的表所有者、sysadmin 固定服务器角色成员以及 db_owner 和 db_ddladmin固定数据库角色成员,并且不可转让。

    若要检索表或视图中的数据,用户必须在表或视图中拥有 SELECT 语句权限。若要更新表或视图的内容,用户必须在表或视图中拥有 INSERT、DELETE 和 UPDATE 语句权限。

    如果视图中存在 INSTEAD OF触发器,用户必须在该视图中有 INSERT、DELETE 和 UPDATE 特权,以对该视图发出 INSERT、DELETE 和 UPDATE 语句,而不管实际上是否在视图上执行了这样的操作。

     
  • 相关阅读:
    es操作
    MySQL逻辑架构
    ceshimd
    mysql资料
    已解决 : VMware Workstation 与 Hyper-V 不兼容。请先从系统中移除 Hyper-V 角色
    MySQL数据库操作
    phpstorm配置laravel语法提示
    MySQL日志之慢查询日志(slow-log)
    456
    topcoder srm 553
  • 原文地址:https://www.cnblogs.com/yujiamin123/p/7081354.html
Copyright © 2011-2022 走看看