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

      

    为什么需要触发器

    为什么需要触发器(TRIGGER)呢?典型的应用就是银行的取款机系统 假定该系统的数据库设计需要两张表:帐户信息表(bank)存放帐户的信息,交易信息表(transInfo)存放每次的交易信息。

     SQL 创建触发器 - Wilson - Wilson

    上述结果有什么错误?您一定发现了,当张三取钱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 
    
                 WHERE 
    
        ELSE
    
            UPDATE bank SET 
    
                 WHERE 
    
        …..
    
    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触发器

    ___________________________________________________________________

    我自己写的触发器

    购买会员卡后,会员绑定卡号,并且升级。

    CREATE TRIGGER trig_update_member
    
     ON club_MemberCard
    
      FOR UPDATE
    
       AS
      DECLARE @membercardpassword varchar(50),@membercardno varchar(50),@membertypeid int,@memberid int,@membercardid int
     select @membercardpassword=password   from     inserted     /*卡号密码*/
     select @membercardno=cardno from  inserted                                /*卡号*/
     select @membertypeid=membertypeid from inserted                     /*类型*/
     select @memberid=memberid from inserted                                 /*用户ID*/
     select @membercardid=id from inserted                                      /*会员卡id*/
     IF UPDATE(memberid)              /* 检查是否修改了交易完成列memberid*/ 
              BEGIN
      if((select membercardno from club_member where ) is null)   /* 检查会员是否第一次购卡*/ 
      begin  
       update club_member set ,
          ,
           
       where ID 
      end
      else
      begin  
       update club_member set 
       where ID 
       update club_membercard set memberid=null
       where 
      end
    
                 END
    
     
    
    CREATE TRIGGER trig_update_membercard
    
     ON dbo.shop_OrderInfo
    
      FOR UPDATE
    
       AS
      DECLARE @memberid bigint,@type int,@orderid int
     select @memberid=memberid   from     inserted                                                    /* 用户ID*/
     select @orderid=id from inserted
     select @type=membertypeid from  shop_goodsinfo where id in (select GoodsID from shop_orderdetail where orderid )   /* 用户类型ID*/
     IF UPDATE(isreceive)              /* 检查是否修改了交易完成列isreceive*/ 
      IF ((select isreceive from shop_orderinfo where id in
      (select orderid from shop_orderdetail where  goodsid in 
       (select id from shop_goodsinfo where goodstypeid=8)) and )=1)
                BEGIN
       update club_membercard set where id in
         (select top 1 id from club_membercard where memberid is null and )
        END
    
    

    --------------------------------------------------------

    短信平台,判断短信内容是否正确

    USE [Msg]
    GO
    
    /****** Object:  Trigger [dbo].[trig_CheckMsg]    Script Date: 11/29/2011 15:29:08 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    -- =============================================
    -- Author:		<Wilson,Chan>
    -- Create date: <2011-11-16,12:19,>
    -- Description:	<判断短信格式是否正确,,>
    -- =============================================
    
    
    CREATE TRIGGER [dbo].[trig_CheckMsg]
    	ON [dbo].[MSG_Inbox]
    	FOR INSERT
    AS
     DECLARE @project_id int,@inorout int,@shop_id int,@inbox_id int
     DECLARE @class1 int,@class2 int,@class3 int,@onduty int
     DECLARE @sender varchar(100),@str varchar(max),@time datetime
     DECLARE @sum int,@test int    --字符串数组个数,待验证的‘店号’
     Select @inbox_id=id from inserted
     select @str=MsgTitle from inserted
     Select @sender=sender from inserted
     select @time=MsgArrivedTime from inserted
     
     BEGIN TRY
    	set @str=REPLACE(@str,',',',')
    	set @str=REPLACE(@str,'0','0')
    	set @str=REPLACE(@str,'1','1')
    	set @str=REPLACE(@str,'2','2')
    	set @str=REPLACE(@str,'3','3')
    	set @str=REPLACE(@str,'4','4')
    	set @str=REPLACE(@str,'5','5')
    	set @str=REPLACE(@str,'6','6')
    	set @str=REPLACE(@str,'7','7')
    	set @str=REPLACE(@str,'8','8')
    	set @str=REPLACE(@str,'9','9')
    	
    	set @sum=dbo.Get_StrArrayLength(@str,',')              --字符串数组个数
    	Set @project_id=dbo.Get_StrArrayStrOfIndex(@str,',',1) --项目代码
    	Set @inorout=dbo.Get_StrArrayStrOfIndex(@str,',',2)    --进店状态
    	Set @shop_id=dbo.Get_StrArrayStrOfIndex(@str,',',3)    --商店代号
    	If (@sum>2 and (@inorout=1 or @inorout=0))
    	begin
    		select @test=shop_id from shop where shop_id=@shop_id
    		If (@test=@shop_id)
    		Begin
    		If (@inorout=0) --离店
    		Begin
    			set @onduty=null
    			if (@sum>3)
    			begin
    				Set @onduty=dbo.Get_StrArrayStrOfIndex(@str,',',4)
    			End
    			update Msg_rightbox 
    			set inorout=@inorout,
    				onduty=@onduty,
    				Outtime=@time
    			where shop_id=@shop_id and inorout=1 and Inbox_id in
    			(select id from Msg_Inbox where Sender=@sender)
    		End	
    		Else
    		Begin --进店
    			Set @class1=null
    			Set @class2=null
    			Set @class3=null
    			If (@sum>3)
    			Begin
    				set @class1=dbo.Get_StrArrayStrOfIndex(@str,',',4) --品类代码1
    			End
    			If (@sum>4)
    			Begin
    				set @class2=dbo.Get_StrArrayStrOfIndex(@str,',',5) --品类代码2
    			End
    			If (@sum>5)
    			Begin
    				set @class3=dbo.Get_StrArrayStrOfIndex(@str,',',6) --品类代码3
    			End
    			
    			
    			insert into Msg_rightbox 
    			(inbox_id,project_id,inorout,shop_id,class1_id,class2_id,class3_id,Intime) 
    			values(@inbox_id,@project_id,@inorout,@shop_id,@class1,@class2,@class3,@time)
    		End
    		end
    		else --****店号错误****
    		begin
    		exec dbo.Sendtipmsg @sender
    		INSERT INTO Msg_wrongbox SELECT * FROM inserted
    		delete from MSG_Inbox where id=@inbox_id
    		end
    	end --****进店状态和或不完整错误****
    	else
    	Begin
    		exec dbo.Sendtipmsg @sender
    		INSERT INTO Msg_wrongbox SELECT * FROM inserted
    		delete from MSG_Inbox where id=@inbox_id
    	End
     END TRY
     BEGIN CATCH --****其他错误****
    	--==发送错误提示短信==
    	exec dbo.Sendtipmsg @sender
    	--==复制短信到WrongBox==
    	INSERT INTO Msg_wrongbox SELECT * FROM inserted
    	delete from MSG_Inbox where id=@inbox_id
     END CATCH
    GO


     

  • 相关阅读:
    activiti eclipse 插件安装
    mysql 改编码
    ubuntu vim 中文乱码
    mac 打开 原生 ntfs 读写
    ubuntu 防止 ssh 超时
    java http
    UITabBarController的一些基础设置
    [转]mac 10.9.4下配置apache
    数组的排序及筛选
    一个UICollectionView自定义layout的实现
  • 原文地址:https://www.cnblogs.com/neso520/p/12491269.html
Copyright © 2011-2022 走看看