zoukankan      html  css  js  c++  java
  • 触发器特殊的存储过程

               

               很多人应该都用过存储过程和触发器,而触发器并不是一个新的概念,它只是一个特殊一些的存储过程, 它可以根据执行的TQL 语句自动执行,不需要我们去调用。

               触发器是为了数据库表结构的完成性、一致性而使用的,和单个表的约束一样,触发器是对于表之间的约束,它比主键约束范围更广泛一些,作用范围更大一些,下面给大家介绍一下常用的三种触发器.

     

               【插入触发器(Insert Trigger)】

               当向表里面插入记录时候触发

               通过临时表(Inserted)来实现,我们需要往表里插入一条记录时,插入的记录先插入到临时表中,然后,从临时表插入到目标表中,为什么采用临时表,我觉的是因为触发器是自动触发,既然是自动触发就不会往里面传参数,那么参数怎么传入到目标表中呢,为了传入参数加入了临时表,将要插入或者删除的记录先放到了临时表中,再从临时表插入数据。

     

              下面是一个校区的基本表TB_Campus,向表里插入数据时触发该触发器,自动向该小区下的建筑表TB_Building添加数据记录,从而保证这两个表的数据一致性。

               触发器通常是为了两个表或多个表中数据一致加入的。

              例如:

    -- =============================================
    -- Author:		评教小组-李龙生
    -- Create date: 2012年12月29日15:02:06
    -- Description:	添加校区记录触发器
    -- =============================================
    CREATE TRIGGER [dbo].[TR_Campus_Add]
    on [dbo].[TB_Campus]
    
    INSTEAD OF INSERT
    
    AS 
    	DECLARE
    	@BuildingID VARCHAR(50),             --建筑物ID
    	@BuildingName VARCHAR(50),           --建筑名
    	@BuildingCode VARCHAR(50),           --建筑代码
    	@Descriptions VARCHAR(500),          --建筑描述
    	@Operator   VARCHAR(50)              --操作人
    
    BEGIN
    	
    	--获取要插入记录的标记号(建筑)
    	SELECT @BuildingID=BuildingID  from inserted  --插入临时表
     
    	--插入基本表中的信息(建筑表)
            INSERT INTO  TB_Building(BuildingID,BuildingCode,BuildingName,Descriptions,Operator)  
    	VALUES(@BuildingID,@BuildingCode,@BuildingName,@Descriptions,@Operator)
    
    END

     

               【更新触发器(Update Trigger)】

                当更新表中的任意一个字段时触发

                更新触发器需要用到两个表,一个是Inserted 表,另一个是Deleted表,Inserted表存储更新后的记录,Deleted表存储更新后的记录,更新一个表示需要先将要删除的记录放入Deleted表中,然后,将Inserted表的新记录插入表中,从而实现更新操作。

     

                例如:下面是教务系统中一个触发器,更新老师课程关系表(TR_TeachCourseLink)记录,并更新与这个表有关的表。

     

                在更新、删除触发器中我们需要注意一个问题,触发器为什么会触发呢,它是基于SQL 语句而执行的,但更新、删除语句可以一次性删除多条记录,其实SQL 语句只执行了一次,即触发器也只执行一次,那么当涉及到表关系为一对多或者多对多时,就会出现更新或删除不完下面表中记录

              

                为了解决这一问题,我们在下面存储过程中加入了游标,使得更新或删除记录时一条一条的删除,每删除一条,触发器就会执行一次,使得数据保持一致,不过,这样可能大大降低了SQL语句执行速度,如果数据量很大,速度会变慢。

     

    USE [BasicDataSystem]
    GO
    /****** Object:  Trigger [dbo].[TR_TeachCourseLink_US]    Script Date: 2013/1/2 19:28:42 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:		评教小组-李龙生
    -- Create date:      2012年12月30日21:03:26
    -- Description:	 假删除授课表中课表记录
    --                   授课课程与虚拟班关系、虚拟班
    --			 授课课程与上课班学生关系、上课班学生
    --                   课程与选修课学生关系、选修课学生
    -- =============================================
    ALTER TRIGGER [dbo].[TR_TeachCourseLink_US]
    	
    	ON [dbo].[TBR_TeachCourseLink]
    
    	AFTER Update
    AS
    	
    	DECLARE
    	@err1 INT,					 --存储错误号
    	@err2 INT,
    	@err3 INT,
    	@err4 INT,
    	@err5 INT,
    	@err6 INT,
    	@err7 INT,
    	@Indexing INT,				 --授课课程主键
    	@TeachClassID VARCHAR(36),   --虚拟班主键
    	@StudentID VARCHAR(36)       --学生主键
    
    BEGIN
    
    	--选择要删除授课课程记录的主键
    	SELECT @Indexing=Indexing FROM  deleted    --删除临时表
    	
    	--开启事务
    	BEGIN TRANSACTION
    
    		/*更新授课课程记录、授课课程与虚拟班关系、虚拟班,各表中的IsAvailable 
    		字段为 “否”*/
    
    		--更新授课课程记录 IsAvailable='否'
    		UPDATE TBR_TeachCourseLink SET IsAvailable='否' WHERE Indexing=@Indexing
    		SET @err1=@@ERROR
    
    		--更新虚拟班与TeachCourse表的关系 IsAvailable='否'
    		UPDATE TBR_CourseTeachClassLink SET IsAvailable='否' WHERE Indexing=@Indexing
    		SET @err2=@@ERROR
    
    		--更新虚拟班表 IsAvailable='否'(需要触发多条记录,用游标操作)
    		--声明游标
    		DECLARE TeachClassCursor CURSOR FOR  
    		SELECT TeachClassID FROM TBR_CourseTeachClassLink  WHERE Indexing=@Indexing 
    		--打开游标
    			OPEN TeachClassCursor
    				FETCH NEXT FROM TeachClassCursor INTO @TeachClassID  --给变量赋初始值
    				WHILE @@FETCH_STATUS=0 --语句执行成功
    					BEGIN
    					--更新中的记录
    					Update TB_TeachClass SET isAvailable = '否' WHERE TeachClassID=@TeachClassID 
    					FETCH NEXT FROM TeachClassCursor INTO @TeachClassID
    					END
    			--关闭并释放游标
    			CLOSE TeachClassCursor
    		DEALLOCATE TeachClassCursor
    		SET @err3=@@ERROR
    
    		/*更新授课课程与选修课学生关系、学生表,各表中的IsAvailable 
    		字段为 “否”*/
    		--更新授课课程与选修课学生的关系表IsAvailable='否'
    		UPDATE TBR_StuChooseCourseLink SET IsAvailable='否' WHERE Indexing=@Indexing
    		SET @err6=@@ERROR
    
    		--更新学生表,将IsAvailable字段变为'否'(需要触发多条记录,用游标操作)
    		--声明游标
    		DECLARE StudentCursor CURSOR FOR  
    		SELECT StudentID FROM TBR_StuChooseCourseLink  WHERE Indexing=@Indexing 
    		--打开游标
    			OPEN StudentCursor
    					FETCH NEXT FROM StudentCursor INTO @StudentID  --给变量赋初始值
    					WHILE @@FETCH_STATUS=0 --语句执行成功
    					begin
    					--更新中的记录
    					Update TB_Student SET isAvailable = '否' WHERE StudentID=@StudentID
    					FETCH NEXT FROM StudentCursor INTO @StudentID
    					end
    			--关闭并释放游标
    			CLOSE StudentCursor
    		DEALLOCATE StudentCursor
    		SET @err7=@@ERROR
    
    	--判断是否执行成功
    	IF (@err1 =0 and @err2=0 and @err3=0 and @err4=0 and @err5=0 and @err6=0 and @err7=0)
    		--提交事务
    		COMMIT TRANSACTION
    	ELSE
    		--事务回滚
    		ROLLBACK TRANSACTION
    
    
    END

     

               【删除触发器(Delete Trigger)】

                当删除表中记录时触发

                先把要删除的记录放到Deleted临时表中,然后,再删除。

                 例如:

    USE [BasicDataSystem]
    GO
    /****** Object:  Trigger [dbo].[TR_TeachCourseLink_D]    Script Date: 2013/1/2 19:29:42 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:		评教小组-李龙生
    -- Create date:      2012年12月30日21:03:26
    -- Description:	彻底删除授课表中课表记录
    --                   课程与选修课学生关系、选修课学生
    -- =============================================
    ALTER TRIGGER [dbo].[TR_TeachCourseLink_D]
    	
    	ON [dbo].[TBR_TeachCourseLink]
    
    	INSTEAD OF DELETE
    AS
    	
    	DECLARE
    	@err1 INT,					 --存储错误号
    	@err2 INT,
    	@err3 INT,
    	@err4 INT,
    	@err5 INT,
    	@err6 INT,
    	@err7 INT,
    	@Indexing INT,				 --授课课程主键
    	@TeachClassID VARCHAR(36),           --虚拟班主键
    	@StudentID VARCHAR(36)               --学生主键
    
    BEGIN
    
    	--选择要删除授课课程记录的主键
    	SELECT @Indexing=Indexing FROM  deleted  --删除临时表
    	
    	--开启事务
    	BEGIN TRANSACTION
    
    		/*删除授课课程记录、授课课程与虚拟班关系、虚拟班 
    		字段为 “否”*/
    
    		--彻底删除授课课程记录
    		DELETE TBR_TeachCourseLink  WHERE Indexing=@Indexing AND IsAvailable='否'
    		SET @err1=@@ERROR
    
    		/*删除授课课程与选修课学生关系、学生表
    		字段为 “否”*/
    		--删除授课课程与选修课学生的关系表
    		DELETE TBR_StuChooseCourseLink   WHERE Indexing=@Indexing and IsAvailable='否'
    		SET @err6=@@ERROR
    
    		--删除学生表(需要触发多条记录,用游标操作)
    		--声明游标
    		DECLARE StudentCursor CURSOR FOR  
    		SELECT StudentID FROM TBR_StuChooseCourseLink  WHERE Indexing=@Indexing 
    		--打开游标
    			OPEN StudentCursor
    					FETCH NEXT FROM StudentCursor INTO @StudentID  --给变量赋初始值
    					WHILE @@FETCH_STATUS=0 --语句执行成功
    					begin
    					--更新中的记录
    					DELETE TB_Student WHERE StudentID=@StudentID and  isAvailable = '否' 
    					FETCH NEXT FROM StudentCursor INTO @StudentID
    					end
    			--关闭并释放游标
    			CLOSE StudentCursor
    		DEALLOCATE StudentCursor
    		SET @err7=@@ERROR
    
    	--判断是否执行成功
    	IF (@err1 =0 and @err2=0 and @err3=0 and @err4=0 and @err5=0 and @err6=0 and @err7=0)
    		--提交事务
    		COMMIT TRANSACTION
    	ELSE
    		--事务回滚
    		ROLLBACK TRANSACTION
    
    
    END


               触发器的工作原理以及什么时候使用两张临时表进行操作,可以用下面这张图表示:Inserted和Deleted两个临时表实现。

     

     

     

     

  • 相关阅读:
    无限级分类表设计
    多表连接
    连接(上接子查询那一篇随笔)
    数据库中常用指令
    子查询
    mysql查询表达式解析
    mysql单表删除记录DELETE
    mysql 单表更新记录UPDATE
    七言
    时分秒计算案例
  • 原文地址:https://www.cnblogs.com/lilongsheng1125/p/4978612.html
Copyright © 2011-2022 走看看