SQL SERVER 从入门到精通 第5版 第三篇 高级应用 第11章 触发器 读书笔记

 第11章 触发器

    >.概述

    触发器是一种特殊类型的存储过程.当指定表中的数据发生变化时触发器自动生效.它与表紧密相连,可以看作表定义的一部分.触发器不能通过名称被直接调用,更不允许设置参数.

    在SQL SERVER 中,一张表可以有多个触发器.用户可以使用INSERT,UPDATE或者DELETE语句对触发器进行设置,也可以对一张表上的特定操作,设置多个触发器.触发器可以包含复杂的SQL语句,不论触发器进行的操作有多复杂,它都只作为一个独立的单元被执行,被看作一个事务.如果在执行触发器的过程中发生了错误,则整个事务将会自动回滚.

    >.触发器的优点.

      >.自动执行.

      >.可以调用一个或者多个存储过程,甚至是数据库之外的外部过程.

      >.能够实现比CHECK约束更为复杂的数据完整性约束.CHECK约束不允许引用其他表中的列来完成检查工作,但触发器可以.

      >.可以检测数据库内的操作,从而取消数据库未经许可的更新操作,使修改与更新更加安全与稳定

      >.能够对数据库中的表进行级联更改.

      >.一个表中可以同时存在3种不同类型的触发器(INSERT,UPDATE,DELETE)

    >.触发器的类型

      >.AFTER触发器:在执行了INSERT,UPDATE或者DELETE语句操作之后执行AFTER触发器.

      >.INSTEAD OF触发器:它是一种特殊类型的数据库触发器,它可以在触发条件满足时代替通常的触发动作。通常的触发动作可能包括插入、更新或删除操作。INSTEAD OF触发器允许你在执行这些操作时定义自定义逻辑,而不是数据库默认的操作。此外,你还可以为一个或多个基表的视图定义INSTEAD OF触发器。这些触发器能够在视图上支持更新操作,扩展视图的功能。这意味着你可以通过视图进行更新操作,并且通过定义适当的INSTEAD OF触发器来处理这些更新,从而实现自定义的行为。

取个例子:

假设你有一个数据库中的视图,名为 SalesSummary,它聚合了销售数据。这个视图可能包含了来自多个表的数据,并提供了一个简化的方式来查看销售总额、平均销售额等信息。

现在,你想要允许用户通过这个视图执行更新操作,例如插入新的销售数据、更新现有销售记录或删除不需要的销售数据。但是,由于视图是基于多个表的聚合,数据库系统无法直接确定如何在这些表上执行这些更新操作。

为了解决这个问题,你可以创建一个INSTEAD OF触发器,它会在用户尝试执行更新操作时代替数据库系统默认的操作。让我们看看如何创建一个简单的INSTEAD OF触发器,以处理对 SalesSummary 视图的更新操作:

-- 创建一个INSTEAD OF触发器来处理对SalesSummary视图的更新操作
CREATE TRIGGER InsteadOfSalesSummaryUpdate
ON SalesSummary
INSTEAD OF INSERT, UPDATE, DELETE
AS
BEGIN
    -- 这里是你自定义的逻辑,你可以根据需要执行任何操作

    -- 示例:在插入新的销售数据之前,你可能想要对数据进行验证
    IF EXISTS (SELECT 1 FROM inserted WHERE SalesAmount < 0)
    BEGIN
        RAISERROR ('Sales amount cannot be negative.', 16, 1);
        ROLLBACK TRANSACTION;
        RETURN;
    END

    -- 示例:在更新销售记录之前,你可能想要记录下谁做了这个更新
    INSERT INTO SalesAuditLog (SalesID, Action, UpdatedBy, UpdatedDateTime)
    SELECT SalesID, 'Update', SYSTEM_USER, GETDATE()
    FROM inserted;

    -- 示例:在删除销售数据之前,你可能需要在其他表中进行相关的清理操作
    DELETE FROM SalesDetails WHERE SalesID IN (SELECT SalesID FROM deleted);

    -- 最后,你可能需要实际执行对基表的更新操作
    -- 例如,对于SalesSummary视图,你可能需要更新多个基表中的相应数据
    -- 但这个更新过程将根据你的数据库架构而不同

    -- 提交事务,表示更新操作已成功完成
    COMMIT TRANSACTION;
END;

在这个例子中,INSTEAD OF触发器 InsteadOfSalesSummaryUpdate 代替了对 SalesSummary 视图的插入、更新和删除操作。你可以根据实际情况扩展这个触发器,以满足你的特定需求。

      >.CLR触发器:CLR触发器可以是AFTER触发器或者INSTEAD OF触发器,还可以是DDL触发器.CLR触发器将执行在托管代码(.NET Framework)中编写的方法,而不用执行SQL存储过程.

      >.DDL触发器:DDL触发器是一种数据库触发器,它会在数据库的结构或模式发生变化时触发。DDL(Data Definition Language)指的是用于定义数据库结构的语言,比如创建、修改或删除表、索引等操作。

与普通的DML(Data Manipulation Language)触发器不同,DDL触发器会在对数据库的结构进行更改时被触发,而不是在对数据进行增删改查时触发。这意味着当执行诸如创建表、删除列等操作时,DDL触发器可以执行特定的逻辑。

举个例子,假设你想要在数据库中创建一个DDL触发器,以便在有新表被创建时记录下创建时间和创建者的信息。以下是一个简单的DDL触发器示例:

-- 创建一个DDL触发器来记录表的创建信息
CREATE TRIGGER DDL_TableCreated
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
    DECLARE @TableName NVARCHAR(128);
    DECLARE @CreatedBy NVARCHAR(128);
    DECLARE @CreatedDateTime DATETIME;

    SET @TableName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(128)');
    SET @CreatedBy = SYSTEM_USER;
    SET @CreatedDateTime = GETDATE();

    -- 在这里你可以将表的创建信息插入到日志表中,或者进行其他自定义的操作
    INSERT INTO TableCreationLog (TableName, CreatedBy, CreatedDateTime)
    VALUES (@TableName, @CreatedBy, @CreatedDateTime);
END;

在这个例子中,DDL触发器 DDL_TableCreated 会在数据库中创建新表时触发。当触发器被激活时,它会获取新创建的表的名称、创建者和创建时间,并将这些信息记录到日志表中。这样,你就可以跟踪数据库中表的创建历史。

  >.创建触发器

    这里要需要说明一下,对 [表] 创建的触发器,会保存在 [表] 下面的触发器里,不是 [可编程性] - [数据库触发器] 下面.如图:

     写完创建过程后,直接点菜单上的 [执行(x)] 即可保存

    警告:触发器也是可以 触发 触发器的!!!这也是为什么大厂不让用触发器的原因 

 

    >.创建DML触发器.如果用户通过DML事件编辑数据,则执行DML触发器.DML事件是针对表或视图的INSERT,UPDATE或者DELETE语句.

-- 创建一个DML触发器,在对指定表进行插入操作时触发
CREATE TRIGGER MyDMLTrigger
ON MyTable
AFTER INSERT
AS
BEGIN
    -- 在这里添加你的逻辑
    -- 例如,记录插入的数据或执行其他操作
    PRINT 'A new row has been inserted into MyTable.';
END;

    >.创建DDL触发器.用于响应各种DDL事件.这结事件主要对应于CREATE,ALTER和DROP语句,以及执行类似DDL操作的某些系统存储过程.

-- 创建一个DDL触发器,在对数据库中创建表时触发
CREATE TRIGGER MyDDLTrigger
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
    -- 在这里添加你的逻辑
    -- 例如,记录表的创建信息或执行其他操作
    PRINT 'A new table has been created in the database.';
END;

    >.创建登录触发器.在遇到 LOGON事件时触发 .LOGON事件是在建立用户会话时触发的.

-- 创建拒绝用户名为'MR'的用户登录的触发器
CREATE TRIGGER trg_Prevent_MR_Login
ON ALL SERVER
FOR LOGON
AS
BEGIN
    DECLARE @UserName NVARCHAR(128);
    SET @UserName = ORIGINAL_LOGIN();

    IF @UserName = 'MR'
    BEGIN
        ROLLBACK;
    END
END;

  >.管理触发器

    一.查看所有触发器

-- 该查询语句用于获取类型为'TR'(即触发器)的对象的名称和定义信息
SELECT 
    name, -- 触发器对象的名称
    definition -- 触发器对象的定义信息
FROM sys.sql_modules AS m
INNER JOIN sys.all_objects AS o ON m.object_id = o.object_id -- 通过INNER JOIN将sys.sql_modules和sys.all_objects连接在一起,条件是object_id匹配
WHERE o.[type] = 'TR'; -- 筛选出类型为'TR'的对象(即触发器),可查看以下官网链接,筛选对应对象之类型

    利用上面的语句,能把当前数据库中所有的触发器展示出来:

下图来源于:sys.sysobjects (Transact-SQL) - SQL Server | Microsoft Learn

 

    书上还提供了另外一种方法来查看所有触发器,但是感觉没上面这种给力:

SELECT * FROM    sys.objects
WHERE type='tr'

 

    二.使用sp_helptext存储过程来查看指定触发器

EXEC sys.sp_helptext 'aaa_ins'

       >.修改触发器

      创建触发器我们用 CREATE TRIGGER 关键字,修改触发器我们用 ALTER TRIGGER关键字来修改即可.

      >.重命名触发器      
EXEC sp_rename 'aaa_ins', 'bbb_ins';
      >.禁用与启用触发器

      被禁用的触发器,并不会被删除掉,而右下角显示一个小红x,以区别启用状态的触发器.可以通过SQL语句设置,也可以通过右键菜单设置

-- 禁用触发器,aaa是一个表名,aaa_ins是触发器
DISABLE TRIGGER aaa_ins ON aaa;

-- 启用触发器
ENABLE TRIGGER aaa_ins ON aaa;

      >.删除触发器

      用DROP TRIGGER关键字删除,也可以通过右键菜单删除 ,aaa是一个表名,aaa_ins是触发器

DROP TRIGGER aaa_ins ON aaa

 

posted @ 2024-04-29 21:16  一曲轻扬  阅读(52)  评论(0编辑  收藏  举报