zoukankan      html  css  js  c++  java
  • SQL Server创建触发器

    为什么需要触发器
    为什么需要触发器(TRIGGER)呢?典型的应用就是银行的取款机系统 假定该系统的数据库设计需要两张表:帐户信息表(bank)存放帐户的信息,交易信息表(transInfo)存放每次的交易信息。
     
    
    上述结果有什么错误?您一定发现了,当张三取钱200元时,虽然交易信息表(transInfo)中保存了取钱200元的交易信息,但帐户表(bank)中的余额仍是1000,没有自动跟随修改。显然,我们应该根据交易类型是“支取”还是“存入”,自动减少或增加帐户表中的余额。而且,它还应该具有事务的特征:一旦交易失败,余额修改也应该自动取消 。那么,如何解决呢?这种特殊的业务规则使用普通约束行吗 ?
    答案显然是否定的 。使用事务行吗?事务能保证一旦交易失败,余额修改也自动取消。但实现不了自动修改的触发功能 。所以,最优的解决方案就是采用触发器。触发器它是一种特殊的存储过程,并且也具有事务的功能,它能在多表之间执行特殊的业务规则或保持复杂的数据逻辑关系 。
     
    什么是触发器
    再看一个例子:目前有两张表,分别存放在职员工和退休员工的信息。
    假定现赵二退休:赵二将从员工表中删除。
    一旦删除赵二的信息,应自动触发一个动作:将赵二的信息保存到退休员工表中。
    强调:自动触发,而不是手动,如何实现呢,当然是使用触发器。
    q       触发器是在对表进行插入、更新或删除操作时自动执行的存储过程
    q       触发器通常用于强制业务规则
    q       触发器是一种高级约束,可以定义比用CHECK 约束更为复杂的约束
    q       可执行复杂的SQL语句(if/while/case)
    q       可引用其它表中的列
    q       触发器定义在特定的表上,与表相关
    q       自动触发执行
    q       不像存储过程,不需要也不能人工调用执行
    q       本身就是一个事务,所以,如果发现有错误,可以回滚撤销操作。
     
    触发器的类型
    INSERT触发器:当向表中插入数据时触发,自动执行触发器所定义的SQL语句。
    UPDATE触发器:当更新表中某列多列时触发,自动执行触发器所定义的SQL语句。
    DELETE触发器:当删除表中记录时触发,自动执行触发器所定义的SQL语句。
     
      inserted 和deleted 表
    q       触发器触发时:
    q       系统自动在内存中创建deleted表或inserted表
    q       只读,不允许修改;触发器执行完成后,自动删除
    q       inserted 表
    q       临时保存了插入或更新后的记录行
    q       可以从inserted表中检查插入的数据是否满足业务需求
    q         如果不满足,则向用户报告错误消息,并回滚插入操作
    q       deleted 表
    q       临时保存了删除或更新前的记录行
    q       可以从deleted表中检查被删除的数据是否满足业务需求
    q         如果不满足,则向用户报告错误消息,并回滚插入操作
    修改操作
    inserted表
    deleted表
    增加(INSERT)记录
    存放新增的记录
    ------
    删除(DELETE)记录
    -----
    存放被删除的记录
    修改(UPDATE)记录
    存放更新后的记录
    存放更新前的记录
    inserted表和deleted表存放的信息
     
    如何创建触发器
    创建触发器的语法:
    CREATE TRIGGER trigger_name
     ON table_name
     [WITH ENCRYPTION]
      FOR [DELETE, INSERT, UPDATE]
     AS
      T-SQL语句
    GO
    WITH ENCRYPTION表示加密触发器定义的SQL文本
    DELETE, INSERT, UPDATE指定触发器的类型
    insert触发器的工作原理:
    1.执行insert插入语句,在表中插入数据行;
    2.触发insert触发器,向系统临时表inserted表中插入新行的备份(副本)
    3.触发器检查inserted表中插入的新行数据,确定是否需要回滚或执行其他操作。
    问题:
    解决上述的银行取款问题:当向交易信息表(transInfo)中插入一条交易信息时,我们应自动更新对应帐户的余额。
     
    分析:
    l        在交易信息表上创建INSERT触发器
    l        从inserted临时表中获取插入的数据行
    l        根据交易类型(transType)字段的值是存入/支取,
    l         增加/减少对应帐户的余额。
    CREATE TRIGGER trig_transInfo
     ON transInfo
      FOR INSERT
       AS
       DECLARE @type char(4),@outMoney MONEY
       DECLARE @myCardID char(10),@balance MONEY
       SELECT @type=transType,@outMoney=transMoney,
             @myCardID=cardID FROM inserted /*从inserted表中获取交易类型、交易金额等*/
         IF (@type='支取') /*根据交易类型,减少或增加对应卡号的余额 */
            UPDATE bank SET currentMoney=currentMoney-@outMoney
                 WHERE cardID=@myCardID
        ELSE
            UPDATE bank SET currentMoney=currentMoney+@outMoney
                 WHERE cardID=@myCardID
        …..
    GO
     
    delete触发器的工作原理:
    1.执行delete删除语句,删除表中的数据行;
    2.触发delete删除触发器,向系统临时表的deleted表中插入被删除的副本
    3.触发器检查deleted表中被删除的数据,确定是否需要回滚或执行其他操作。
    问题:
    当删除交易信息表时,要求自动备份被删除的数据到表backupTable中 。
     
    分析:
    l        在交易信息表上创建DELETE触发器
    l        被删除的数据可以从deleted表中获取
    CREATE TRIGGER trig_delete_transInfo
     ON transInfo
      FOR DELETE
       AS
          print '开始备份数据,请稍后......'
          IF NOT EXISTS(SELECT * FROM sysobjects
               WHERE name='backupTable')
             SELECT * INTO backupTable FROM deleted/*从deleted表中获取被删除的交易记录*/
         ELSE
             INSERT INTO backupTable SELECT * FROM deleted
          print '备份数据成功,备份表中的数据为:'
          SELECT * FROM backupTable
    GO
     
    UPDATE触发器的工作原理:
    执行更新操作,例如把李四的余额改为20001元。
    更新操作可以看出两步:
    1.删除李四原有的数据:李四 1000 0002  1,将数据备份到deleted表中。
    2.再插入新行:李四 1000 0002  20001,将数据备份到inserted表中。
    最后看起来就是把余额从1元修改为20001元了。
    所以:如果我们希望查看修改前的原始数据,可以查看表deleted 。
    如果我们希望查看修改后的数据,可以查看表inserted 。
    问题:
    跟踪用户的交易,交易金额超过20000元,则取消交易,并给出错误提示。
     
    分析:
    l        在bank表上创建UPDATE触发器
    l        修改前的数据可以从deleted表中获取
    l        修改后的数据可以从inserted表中获取
    CREATE TRIGGER trig_update_bank
     ON bank
      FOR UPDATE
       AS
          DECLARE @beforeMoney MONEY,@afterMoney MONEY 
    /*从deleted表中获取交易前的余额,从inserted表中获取交易后的余额*/
          SELECT @beforeMoney=currentMoney FROM deleted  
          SELECT @afterMoney=currentMoney FROM inserted   
          IF ABS(@afterMoney-@beforeMoney)>20000 /*交易金额是否>2万*/
            BEGIN
                print '交易金额:'+convert(varchar(8),
                    ABS(@afterMoney-@beforeMoney))
                RAISERROR ('每笔交易不能超过2万元,交易失败',16,1)
                ROLLBACK TRANSACTION /*回滚事务,撤销交易*/
             END
    GO
     
    列级 UPDATE 触发器
    q       UPDATE触发器除了跟踪数据的变化(修改)外,还可以检查是否修改了某列的数据
    q       使用UPDATE()(列)函数检测是否修改了某列
    问题:
    交易日期一般由系统自动产生,默认为当前日期。为了安全
    起见,一般禁止修改,以防舞弊。
     
    分析:
    UPDATE(列名)函数可以检测是否修改了某列
    CREATE TRIGGER trig_update_transInfo
     ON transInfo
      FOR UPDATE
       AS
          IF UPDATE(transDate)/* 检查是否修改了交易日期列transDate*/
             BEGIN
                print '交易失败.....'
                RAISERROR (‘安全警告:交易日期不能修改,
                               由系统自动产生',16,1)
                ROLLBACK TRANSACTION   /*回滚事务,撤销交易*/
             END
    GO
     
    好,我们来做个总结:
    q       触发器是在对表进行插入、更新或删除操作时自动执行的存储过程,触发器通常用于强制业务规则
    q       触发器还是一个特殊的事务单元,当出现错误时,可以执行ROLLBACK TRANSACTION回滚撤销操作
    q       触发器一般都需要使用临时表:deleted表和inserted表,它们存放了被删除或插入的记录行副本
    q       触发器类型:
    q        INSERT触发器
    q        UPDATE触发器
    q        DELETE触发器
  • 相关阅读:
    多个类定义attr属性重复的问题:Attribute "xxx" has already been defined
    好用的批量改名工具——文件批量改名工具V2.0 绿色版
    得到ImageView中drawable显示的区域的计算方法
    得到view坐标的各种方法
    实现类似于QQ空间相册的点击图片放大,再点后缩小回原来位置
    Material Designer的低版本兼容实现(五)—— ActivityOptionsCompat
    Android 自带图标库 android.R.drawable
    解决 Attempting to destroy the window while drawing!
    解决Using 1.7 requires compiling with Android 4.4 (KitKat); currently using API 4
    Material Designer的低版本兼容实现(四)—— ToolBar
  • 原文地址:https://www.cnblogs.com/ruishuang208/p/4094015.html
Copyright © 2011-2022 走看看