sql 触发器操作详解

触发器对表进行插入、更新、删除的时候会自动执行的特殊存储过程。触发器一般用在check约束更加复杂的约束上面。触发器和普通的存储过程的区别是:触发器是当对某一个表进行操作。诸如:update、insert、delete这些操作的时候,系统会自动调用执行该表上对应的触发器。SQL Server 2005中触发器可以分为两类:DML触发器和DDL触发器,其中DDL触发器它们会影响多种数据定义语言语句而激发,这些语句有create、alter、drop语句。

  常见的触发器有三种:分别应用于Insert , Update , Delete 事件。

      我为什么要使用触发器?比如,这么两个表:

  

    Create Table Student(              --学生表
        StudentID int primary key,       --学号
        ....
       )

      Create Table BorrowRecord(               --学生借书记录表
        BorrowRecord   int identity(1,1),       --流水号  
        StudentID      int ,                    --学号
        BorrowDate     datetime,                --借出时间
        ReturnDAte     Datetime,                --归还时间
        ...
      )

     用到的功能有:
        1.如果我更改了学生的学号,我希望他的借书记录仍然与这个学生相关(也就是同时更改借书记录表的学号);
        2.如果该学生已经毕业,我希望删除他的学号的同时,也删除它的借书记录。
     等等。

     这时候可以用到触发器。对于1,创建一个Update触发器:

   

  Create Trigger truStudent
       On Student                         --在Student表中创建触发器
       for Update                          --为什么事件触发
     As                                        --事件触发后所要做的事情
       if Update(StudentID)           
       begin

         Update BorrowRecord
           Set StudentID=i.StudentID
           From BorrowRecord br , Deleted   d ,Inserted i      --Deleted和Inserted临时表
           Where br.StudentID=d.StudentID

       end       
                

     理解触发器里面的两个临时的表:Deleted , Inserted 。注意Deleted 与Inserted分别表示触发事件的表“旧的一条记录”和“新的一条记录”。
     一个数据库教程系统中有两个虚拟表用于存储在表中记录改动的信息,分别是:
                             虚拟表Inserted                     虚拟表Deleted

在表记录新增时     存放新增的记录                         不存储记录
         修改时           存放用来更新的新记录                   存放更新前的记录
         删除时           不存储记录                             存放被删除的记录

     一个Update 的过程可以看作为:生成新的记录到Inserted表,复制旧的记录到Deleted表,然后删除Student记录并写入新纪录。

 

    对于2,创建一个Delete触发器
     Create trigger trdStudent
       On Student
       for Delete
     As
       Delete BorrowRecord
         From BorrowRecord br , Delted d
         Where br.StudentID=d.StudentID

    

从这两个例子我们可以看到了触发器的关键:A.2个临时的表;B.触发机制

    DML触发器分为:

    1、 after触发器(之后触发)

        a、 insert触发器

        b、 update触发器

        c、 delete触发器

 

    2、 instead of 触发器 (之前触发)

 

    其中after触发器要求只有执行某一操作insert、update、delete之后触发器才被触发,且只能定义在表上。而instead of触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。既可以在表上定义instead of触发器,也可以在视图上定义。

 

    触发器有两个特殊的表:插入表(instered表)和删除表(deleted表)。这两张是逻辑表也是虚表。有系统在内存中创建者两张表,不会存储在数据库中。而且两张表的都是只读的,只能读取数据而不能修改数据。这两张表的结果总是与被改触发器应用的表的结构相同。当触发器完成工作后,这两张表就会被删除。Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据。

 


对表的操作

Inserted逻辑表

Deleted逻辑表

增加记录(insert)

存放增加的记录


删除记录(delete)


存放被删除的记录

修改记录(update)

存放更新后的记录

存放更新前的记录

    Update数据的时候就是先删除表记录,然后增加一条记录。这样在inserted和deleted表就都有update后的数据记录了。注意的是:触发器本身就是一个事务,所以在触发器里面可以对修改数据进行一些特殊的检查。如果不满足可以利用事务回滚,撤销操作。

 

Ø 创建触发器

 

   语法

create trigger tgr_nameon table_namewith encrypion –加密触发器    for update...as    Transact-SQL

    # 创建insert类型触发器

--创建insert插入类型触发器if (object_id('tgr_classes_insert', 'tr') is not null)    drop trigger tgr_classes_insertgocreate trigger tgr_classes_inserton classes    for insert --插入触发as    --定义变量    declare @id int, @name varchar(20), @temp int;    --在inserted表中查询已经插入记录信息    select @id = id, @name = name from inserted;    set @name = @name + convert(varchar, @id);    set @temp = @id / 2;        insert into student values(@name, 18 + @id, @temp, @id);    print '添加学生成功!';go--插入数据insert into classes values('5班', getDate());--查询数据select * from classes;select * from student order by id;

     insert触发器,会在inserted表中添加一条刚插入的记录。

 

    # 创建delete类型触发器

--delete删除类型触发器if (object_id('tgr_classes_delete', 'TR') is not null)    drop trigger tgr_classes_deletegocreate trigger tgr_classes_deleteon classes    for delete --删除触发as    print '备份数据中……';        if (object_id('classesBackup', 'U') is not null)        --存在classesBackup,直接插入数据        insert into classesBackup select name, createDate from deleted;    else        --不存在classesBackup创建再插入        select * into classesBackup from deleted;    print '备份数据成功!';go----不显示影响行数--set nocount on;delete classes where name = '5班';--查询数据select * from classes;select * from classesBackup;

   delete触发器会在删除数据的时候,将刚才删除的数据保存在deleted表中。

 

    # 创建update类型触发器

--update更新类型触发器if (object_id('tgr_classes_update', 'TR') is not null)    drop trigger tgr_classes_updategocreate trigger tgr_classes_updateon classes    for updateas    declare @oldName varchar(20), @newName varchar(20);    --更新前的数据    select @oldName = name from deleted;    if (exists (select * from student where name like '%'+ @oldName + '%'))        begin            --更新后的数据            select @newName = name from inserted;            update student set name = replace(name, @oldName, @newName) where name like '%'+ @oldName + '%';            print '级联修改数据成功!';        end    else        print '无需修改student表!';go--查询数据select * from student order by id;select * from classes;update classes set name = '五班' where name = '5班';

     update触发器会在更新数据后,将更新前的数据保存在inserted表中,更新后的数据保存在inserted表中。

 

    # update更新列级触发器

if (object_id('tgr_classes_update_column', 'TR') is not null)    drop trigger tgr_classes_update_columngocreate trigger tgr_classes_update_columnon classes    for updateas    --列级触发器:是否更新了班级创建时间    if (update(createDate))    begin        raisError('系统提示:班级创建时间不能修改!', 16, 11);        rollback tran;    endgo--测试select * from student order by id;select * from classes;update classes set createDate = getDate() where id = 3;update classes set name = '四班' where id = 7;

     更新列级触发器可以用update是否判断更新列记录;

 

    # instead of类型触发器

       instead of触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身的内容。

       创建语法

create trigger tgr_nameon table_namewith encryption    instead of update...as    T-SQL

   

      # 创建instead of触发器

if (object_id('tgr_classes_inteadOf', 'TR') is not null)    drop trigger tgr_classes_inteadOfgocreate trigger tgr_classes_inteadOfon classes    instead of delete/*, update, insert*/as    declare @id int, @name varchar(20);    --查询被删除的信息,病赋值    select @id = id, @name = name from deleted;    print 'id: ' + convert(varchar, @id) + ', name: ' + @name;    --先删除student的信息    delete student where cid = @id;    --再删除classes的信息    delete classes where id = @id;    print '删除[ id: ' + convert(varchar, @id) + ', name: ' + @name + ' ] 的信息成功!';go--testselect * from student order by id;select * from classes;delete classes where id = 7;

   

      # 显示自定义消息raiserror

if (object_id('tgr_message', 'TR') is not null)    drop trigger tgr_messagegocreate trigger tgr_messageon student    after insert, updateas raisError('tgr_message触发器被触发', 16, 10);go--testinsert into student values('lily', 22, 1, 7);update student set sex = 0 where name = 'lucy';select * from student order by id;

    # 修改触发器

alter trigger tgr_messageon studentafter deleteas raisError('tgr_message触发器被触发', 16, 10);go--testdelete from student where name = 'lucy';

    # 启用、禁用触发器

--禁用触发器disable trigger tgr_message on student;--启用触发器enable trigger tgr_message on student;

    # 查询创建的触发器信息

--查询已存在的触发器select * from sys.triggers;select * from sys.objects where type = 'TR';

--查看触发器触发事件select te.* from sys.trigger_events te join sys.triggers ton t.object_id = te.object_idwhere t.parent_class = 0 and t.name = 'tgr_valid_data';

--查看创建触发器语句exec sp_helptext 'tgr_message';

 

    # 示例,验证插入数据

if ((object_id('tgr_valid_data', 'TR') is not null))    drop trigger tgr_valid_datagocreate trigger tgr_valid_dataon studentafter insertas    declare @age int,            @name varchar(20);    select @name = s.name, @age = s.age from inserted s;    if (@age < 18)    begin        raisError('插入新数据的age有问题', 16, 1);        rollback tran;    endgo--testinsert into student values('forest', 2, 0, 7);insert into student values('forest', 22, 0, 7);select * from student order by id;

    # 示例,操作日志

if (object_id('log', 'U') is not null)    drop table loggocreate table log(    id int identity(1, 1) primary key,    action varchar(20),    createDate datetime default getDate())goif (exists (select * from sys.objects where name = 'tgr_student_log'))    drop trigger tgr_student_loggocreate trigger tgr_student_logon studentafter insert, update, deleteas    if ((exists (select 1 from inserted)) and (exists (select 1 from deleted)))    begin        insert into log(action) values('updated');    end    else if (exists (select 1 from inserted) and not exists (select 1 from deleted))    begin        insert into log(action) values('inserted');    end    else if (not exists (select 1 from inserted) and exists (select 1 from deleted))    begin        insert into log(action) values('deleted');    endgo--testinsert into student values('king', 22, 1, 7);update student set sex = 0 where name = 'king';delete student where name = 'king';select * from log;select * from student order by id;

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索数据
, 触发器
, null
类型
计划任务 触发器详解、db2触发器详解、mysql触发器详解、oracle触发器详解、zabbix触发器详解,以便于您获取更多的相关知识。

时间: 2024-09-20 05:53:59

sql 触发器操作详解的相关文章

PostgreSQL 触发器 用法详解 1

标签 PostgreSQL , trigger , 触发器 , 用法详解 背景 触发器在数据库中的应用非常广泛,例如在发生insert, update, delete, truncate时触发,调用事先写好的触发器函数. 触发器函数可以使用plpgsql , c , python , perl , java等语言编写. 触发器函数中支持很多内置的变量,可以干很多事情. 本文将以PostgreSQL 9.2为例, 介绍触发器的使用. 分两部分. 第二部分链接 : 内容简介 一. 1. 什么是触发器

Mysql事项,视图,函数,触发器命令(详解)_Mysql

事项开启和使用 //修改表的引擎 alter table a engine=myisam; //开启事务 begin; //关闭自动提交 set autocommit=0; //扣100 update bank set money=money-100 where bid=1; //回滚,begin开始的所有sql语句操作 rollback; //开启事务 begin; //关闭自动提交 set autocommit=0; //扣100 update bank set money=money-10

PHP数组游标实现对数组的各种操作详解_php技巧

本文实例分析了PHP数组游标实现对数组的各种操作.分享给大家供大家参考,具体如下: 如何不用foreach实现对数组实现循环? 答:我们只需要模拟foreach就行了,数组在执行foreach循环的时候,是有一个游标指向当前数组循环到的值, 那如果我们能拿到这个游标,并且操作游标,使游标前进或者后退,那么我们就能不用foreach而实现循环数组 直接上代码,清晰直观: <?php $arr = array('你','若','安','好','便','是','晴','天'); //current()

Yii多表联合查询操作详解_php实例

本文针对Yii多表联查进行汇总描述,供大家参考,具体内容如下 1.多表联查实现方法 有两种方式一种使用DAO写SQL语句实现,这种实现理解起来相对轻松,只要保证SQL语句不写错就行了.缺点也很明显,比较零散,而且不符合YII的推荐框架,最重要的缺点在于容易写错. 还有一种便是下面要说的使用YII自带的CActiveRecord实现多表联查 2. 整体框架 我们需要找到一个用户的好友关系,用户的信息放在用户表中,用户之间的关系放在关系表中,而关系的内容则放在关系类型表中.明显的我们只需要以关系表为

使用技巧:对Java编程中的文件操作详解

编程|技巧|详解 一.获得控制台用户输入的信息 /** *//**获得控制台用户输入的信息 * @return * @throws IOException */ public String getInputMessage() throws IOException...{ System.out.println("请输入您的命令∶"); byte buffer[]=new byte[1024]; int count=System.in.read(buffer); char[] ch=new

C 和 C++ 文件操作详解

来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html 来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html C++的文件操作 在C++中,有一个stream这个类,所有的I/O都以这个"流"类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符: 1.插入器(<<) 向流输出数据.比如说系统有一

ajax 异步数据操作详解(1/3)

ajax 异步数据操作详解 AJAX全称为"Asynchronous JavaScript and XML"(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. 主要包含了以下几种技术: Ajax(Asynchronous JavaScript + XML)的定义 基于web标准(standards-based presentation)XHTML+CSS的表示: 使用 DOM(Document Object Model)进行动态显示及交互: 使用 XML

javascript jquery对form元素的常见操作详解_javascript技巧

1.下拉框 select : 移除option $("#ID option").each(function(){ if($(this).val() == 111){ $(this).remove(); } }); 添加option $("<option value='111'>UPS Ground</option>").appendTo($("#ID")); 取得下拉选单的选取值 //取下拉選中的文本 $('#testSe

Jquery基础之事件操作详解_jquery

事件是用户操作时页面或页面加载时引发的用来完成javascript和HTML之间的交互操作.常见的元素点击事件.鼠标事件.键盘输入事件等,较传Javascript 相比JQuery增加并扩展了基本的事件处理机制,极大的增强了事件处理的能力. 一.DOM加载事件 页面加载完毕后浏览器会通过javascript为Dom元素加载事件,使用Javascript时候使用的是window.onload方法,而Jquery使用的是$(document).ready()方法,下表 展示两个事件的异同. wind