一、触发器概念

1.1、触发器特征

        1.1.1、触发器是在对表进行增、删、改时,自动执行的存储过程。触发器常用于强制业务规则,它是一种高级约束,通过事件进行触发而被执行。

        1.1.2、触发器是一个特殊的事务单元,可以引用其他表中的列执行特殊的业务规则或数据逻辑关系。当出现错误时,可以执行rollback transaction操作将整个触发器以及触发它的T-SQL语句一并回滚(不需显示声明begin transaction)。

        1.1.3、每个触发器将用到的两个临时表:

deleted 临时表:用于临时存放被删除的记录行副本(包括delete和update语句所影响的数据行);
                  注意:被删除的记录行,首先从原始表中删除,并保存到触发器表。然后从触发器表中删除,再保存到deleted表。
inserted 临时表:用于临时存放插入的记录行副本(包括insert和update语句所影响的数据行);
deleted表和inserted表的特征:
    > 这两个表的表结构与该触发器作用的表相同;
    > 这两个表是逻辑表,并且由系统管理;
    > 这两个表是动态驻留在内存中的(不是存储在数据库中),当触发器工作完成后,它们也被删除;
    > 这两个表是只读的,即只能运用select语句查看(用户不能直接更改);
        1.1.4、所创建的触发器(insert、delete、update)是在原表数据行已经修改完成后再触发。所以,触发器是在约束检查之后才执行。

1.2、什么时候用触发器?

a、实现主外键关系所不能保证的复杂参照完整性和数据的一致性。
    不过,通过“级联引用完整性约束”可以更有效地执行这些更改。
b、防止恶意或错误的 INSERT、UPDATE 以及 DELETE 操作,并强制执行比 CHECK 约束定义的限制更为复杂的其他限制。
   > 与 CHECK 约束不同(check约束只能引用自身表中的列),DML触发器可以引用其他表中的列;
   > 触发器可以完成所有约束的功能,但不一定是最佳方案;
   > 触发器能够使用自定义信息和较为复杂的错误处理;
c、DML 触发器可以评估数据修改前后表的状态,并根据该差异采取措施。
d、一个表中的同一个修改语句的DML触发器,允许被多个不同的操作(INSERT、UPDATE 或 DELETE)来响应;

1.3、触发器的类型:
insert 触发器;(略)
delete 触发器;(略)
update 触发器:在修改表中记录行或某列数据时触发执行;
注意:update(列)函数:实现检测某列是否被修改。
update 更新操作分为两步:
首先,“删除”更改前原有数据行:删除的原有数据行将复制到deleted临时表中;
然后,“插入”更改后的新数据行:插入新数据行到原始表,同时将新数据行保存到inserted临时表和触发器表中;
1.4、创建触发器的注意点:
     1.4.1、create trigger必须是批处理(go)的第一条语句;
     1.4.2、一个触发器语句只能用到一个表或一个视图中;
   on 表名/ 视图名
     1.4.3、一个触发器语句可以执行多个操作;
   for delete,insert,update -- 无先后顺序的任意组合
     1.4.4、建议DML触发器不返回任何结果。这是因为对这些返回结果的特殊处理必须写入每个允许对触发器表进行修改的应用程序中。
     若要防止从 DML 触发器返回任何结果,请不要在触发器定义中包含select语句或变量赋值;
     如果必须在触发器中进行变量赋值,则应该在触发器被触发之前使用set nocount on语句以避免返回任何结果集;
注意:未来版本的SQL Server 中,将会删除从触发器返回结果集的功能。
      1.4.5、如果“触发器表”本身也存在约束,则在执行insert、delete、update触发器前,首先会检查“触发器表”上存在的约束。如果不满足约束,则不会执行其insert、delete、update触发器。

1.5、查看当前数据库中的所有触发器

select * from sys.triggers

二、触发器实例

2.1、初始化表

--------------- 初始化环境 ---------------

create database TriggerDatabase
use TriggerDatabase
go if exists(select * from sysobjects where name='bank')
drop table bank create table bank -- 账户信息表
(
userName varchar(10) not null, --顾客名
cardID varchar(10) not null, --卡号
currentMoney money not null --当前余额
) if exists(select * from sysobjects where name='transInfo')
drop table transInfo create table transInfo --交易信息表
(
cardID varchar(10) not null, --卡号
transType char(4) not null, --交易类型(存入/支取)
transMoney money not null, --交易金额
transDate datetime not null --交易日期
)
go --------------- 添加约束 ---------------
alter table bank
add constraint CK_currentMoney check(currentMoney>=1); alter table transInfo
add constraint DF_transDate default(getdate()) for transDate; alter table transInfo
add constraint CK_transType check(transType in('支取','存入')); --------------- 添加测试数据 ---------------
/* 张三 1000元 */
insert into bank(userName,cardID,currentMoney)
values('张三','1001 0001',1000);
/* 李四 1元 */
insert into bank(userName,cardID,currentMoney)
values('李四','1001 0002',1);
/* 张三 支取 200元 */
insert into transInfo(cardID,transType,transMoney)
values('1001 0001','支取',200); --------------- 查看结果 ---------------
select * from bank;
select * from transInfo;
go

2.2、触发器格式

create trigger [ schema_name. ] -- 触发器所属架构
trigger_name -- 触发器名称
on { table | view } -- 触发器的表或视图
[ with encryption ] -- 加密dml触发器定义(后面详解)
{ for | after }
/* after:只有在触发它的SQL语句执行成功后才能激发。
(只能对“表”定义after) */
{ insert,update,delete }
as
/* SQL语句... */
go --查看当前数据库中的所有触发器
select * from sys.triggers

2.3、Insert 触发器

------------------ insert 触发器 ------------------
use TriggerDatabase
go
if exists(select * from sysobjects
where name='trig_insert_transInfo')
drop trigger trig_insert_transInfo
go -- create trigger必须是批处理(go)的第一句 create trigger trig_insert_transInfo
on transInfo for insert
as
declare @_transType char(4), --定义变量
@_transMoney money,
@_cardID char(10),
@balance money --所剩余额 -- 从inserted临时表中获取记录值
select @_transType = transType,
@_transMoney = transMoney,
@_cardID = cardID
from inserted
    if(@_transType = '支取')
update bank set currentMoney=currentMoney-@_transMoney
where cardID = @_cardID;
else
update bank set currentMoney=currentMoney+@_transMoney
where cardID = @_cardID; --显示交易金额
print '交易成功! 交易金额:'
+ convert(varchar(20),@_transMoney) --显示所剩余额
select @balance = currentMoney from bank
where cardId = @_cardID print '卡号:'+@_cardID
+ ' 余额:'+convert(varchar(20),@balance);
go ------------------ 测试触发器 ------------------
-- delete from transInfo
set nocount on --不显示T-SQL影响的记录行数 insert into transInfo(cardID,transType,transMoney)
values('1001 0001','支取',200);
insert into transInfo(cardID,transType,transMoney)
values('1001 0001','存入',10000);
--查看结果
select * from bank
select * from transInfo
复制代码

2.4、delete 触发器

/* 实现: 当清除'交易信息表'的数据时,
自动备份被清除的数据到backupTable表中
*/ ------------------ delete 触发器 ------------------
use TriggerDatabase
go if exists (select * from sysobjects
where name='trig_delete_transInfo')
drop trigger trig_delete_transInfo
go create trigger trig_delete_transInfo
on transInfo after delete -- for | after
as
print '开始备份数据,请稍后......'
-- 如果数据库中,不存在 backupTable 表
if not exists(select * from sysobjects
where name='backupTable')
select * into backupTable from deleted --deleted临时表
else
insert into backupTable select * from deleted print '备份成功,备份表 backupTable 中的数据为:'
select * from backupTable;
go ------------------ 测试触发器 ------------------
set nocount on delete from transInfo; --测试 --查看结果
select * from transInfo
select * from backupTable

2.5、update 触发器

------------------ update 触发器 ------------------
use TriggerDatabase
go if exists (select * from sysobjects
where name='trig_update_bank')
drop trigger trig_update_bank
go create trigger trig_update_bank
on bank for update --在bank表上创建update触发器
as
declare @beforeMoney money,
@afterMoney money,
@currentTrans money --当前交易金额 --从deleted临时表,获取交易前的余额
select @beforeMoney = currentMoney from deleted;
--从inserted临时表,获取交易后的余额
select @afterMoney = currentMoney from inserted; if abs(@afterMoney-@beforeMoney) > 2000
begin
print '当前交易金额为:' +
convert(varchar(20),abs(@afterMoney-@beforeMoney))
-- 自定义错误消息
raiserror('每次交易金额不能超过2000元,交易失败!',16,1) rollback transaction --回滚事务,撤销交易!
/* 注意:
触发器是一个特殊的事务单元
不需显示声明begin transaction
*/
end
go ------------------ 测试触发器 ------------------
set nocount on --测试1: 在 bank表触发 update触发器
update bank set currentMoney = currentMoney + 25000
where cardID = '1001 0001' --测试2: 通过 transInfo表的 trig_insert_transInfo触发器
-- 间接触发 bank表的 trig_update_bank触发器 insert into transInfo(cardID,transType,transMoney)
values('1001 0001','存入',10000); --查看结果
select * from bank
select * from transInfo

2.6、MSDN参考

     2.6.1、加密 dml触发器定义
      若要确保其他用户不能查看触发器定义,可以使用with encryption子句加密 dml 触发器。
      使用with encryption子句后,触发器定义即以无法读取的格式进行存储。
      触发器定义加密后,无法进行解密。且任何人都无法进行查看,包括触发器的所有者和系统管理员。

     2.6.2、update() 函数:
      可用于确定 insert或 update语句是否影响表中的特定列。
      无论何时为列赋值,该函数都将返回 true。

使用if update() 子句示例:

create table testTable(a int null, b int null)
go
create trigger my_trig
on testTable for insert
as
if update(b)
print '列b已被修改!'
go insert into testTable(b) values(123); -- drop table testTable

注意: 
      由于 delete 语句无法只对某列进行删除,
      因此不能将if update()子句应用于delete 语句。

     2.6.3、columns_updated() 函数:
      也可用于检查 insert或 update语句更新了表中的哪些列。
      此函数使用整数位掩码指定要测试的列。

使用columns_updated() 函数示例:

create table testTable2(a int null, b int null)
go create trigger my_trig2
on testTable2 for insert
as
if ( columns_updated() & 2 = 2 )
print '列b已被修改!'
go insert into testTable2(b) values(123); -- drop table testTable2

转载:http://www.cnblogs.com/xugang/archive/2010/02/20/1669619.html

浅谈 Sql Server 触发器的更多相关文章

  1. 【SqlServer系列】浅谈SQL Server事务与锁(上篇)

    一  概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章视图采用图文的方式来与大家一起探讨. “浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及 ...

  2. 浅谈SQL Server内部运行机制

    对于已经很熟悉T-SQL的读者,或者对于较专业的DBA来说,逻辑的增删改查,或者较复杂的SQL语句,都是非常简单的,不存在任何挑战,不值得一提,那么,SQL的哪些方面是他们的挑战 或者软肋呢? 那就是 ...

  3. 浅谈SQL Server数据内部表现形式

    在上篇文章 浅谈SQL Server内部运行机制 中,与大家分享了SQL Server内部运行机制,通过上次的分享,相信大家已经能解决如下几个问题: 1.SQL Server 体系结构由哪几部分组成? ...

  4. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  5. 浅谈SQL Server事务与锁(上篇)

    一  概述 在数据库方面,对于非DBA的程序员来说,事务与锁是一大难点,针对该难点,本篇文章试图采用图文的方式来与大家一起探讨. “浅谈SQL Server 事务与锁”这个专题共分两篇,上篇主讲事务及 ...

  6. 浅谈SQL Server中的事务日志(一)----事务日志的物理和逻辑构架

    简介 SQL Server中的事务日志无疑是SQL Server中最重要的部分之一.因为SQL SERVER利用事务日志来确保持久性(Durability)和事务回滚(Rollback).从而还部分确 ...

  7. 浅谈SQL Server 对于内存的管理

    简介 理解SQL Server对于内存的管理是对于SQL Server问题处理和性能调优的基本,本篇文章讲述SQL Server对于内存管理的内存原理. 二级存储(secondary storage) ...

  8. (转)浅谈SQL Server 对于内存的管理

    简介 理解SQL Server对于内存的管理是对于SQL Server问题处理和性能调优的基本,本篇文章讲述SQL Server对于内存管理的内存原理. 二级存储(secondary storage) ...

  9. 浅谈SQL Server中的三种物理连接操作

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...

随机推荐

  1. Python学习手册之Python介绍、基本语法(一)

    一.什么是python? python是一种高级的编程语言.它适合编写一些应用程序,比如:网站编程,脚本编程,科学计算和最近非常热门的AI(人工智能).目前,Google,腾讯,百度,阿里巴巴,豆瓣都 ...

  2. 【 C 】高级字符串查找之查找标记(token)函数 strtok介绍

    我的csdn博客 一个字符串常常包含几个单独的部分,它们彼此被分隔开来.每次为了处理这些部分,你首先必须把它们从字符串中抽取出来. 这个任务有#include<string.h>中的str ...

  3. 20155224 《实验二 Java面向对象程序设计》实验报告

    实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验要求 没有Linux ...

  4. 初步安装配置虚拟机、Ubuntu、git、vim、码云项目

    内容 虚拟机软件:Oracle VM VirtualBox 系统:Ubuntu 配置:git:码云;vim 过程 下载安装VirtualBox.ubuntu 根据链接-- 基于VirtualBox安装 ...

  5. texterea 水平居中

    例子:<div style="width: 100%;text-align: center;"> <textarea class="xinde_msg& ...

  6. OpenCV人脸识别-训练级联分类器

    OpenCV中以及附带了训练好的人脸特征分类器,3.2版本的有三种: 分别是LBP,Haar,Hug 在Data目录下. 也可以训练自己的特征库,具体参照如下: 级联分类器训练 — OpenCV 2. ...

  7. Redis可视化客户端管理Web UI工具收集

    https://github.com/uglide/RedisDesktopManager(推荐,全平台支持的桌面UI工具) Web方案: https://github.com/ErikDubbelb ...

  8. 【搜索好题】bzoj1501 [NOI2005]智慧珠游戏

    bzoj1501 [NOI2005]智慧珠游戏 搜索苟逼题系列. 暴力枚举每一种情况(包括旋转翻转全都考虑在内)然后码出代码. (正解似乎不是这样子的) 那年好像还有平衡树苟逼题维护数列233333心 ...

  9. php实现图形计算器

    存档: index.php <html> <head> <title>图形计算器开发</title> <meta http-equiv=" ...

  10. MYSQL存储过程调试过程

     mysql不像oracle有plsqldevelper工具用来调试存储过程,所以有几种简单的方式追踪执行过程: 1.用一张临时表,记录调试过程: 2.直接在存储过程中,增加select xxx,在控 ...