器分

SQLServer 中,触器可以分两大DML 器和DDL

DML 器:

DML器是当数据器中生数据操作言(Data Manipulation

Language)事件时执行的存储过程。

DML 器又分After 器和Instead Of

1 After 器:这类器是在记录完之后(after),才会被激活行,它主要是用于记录变更后的理或检查,一旦发现错误,也可以用RollbackTransaction 句来回本次的操作。即AFTER 器在INSERTUPDATEDELETE 句的操作之后

2 InsteadOf 器:这类器一般是用来取代原本的操作,在记录变更之生的,它并不去行原来SQL 句里的操作(InsertUpdateDelete),

而去行触器本身所定的操作。INSTEADOF 器代替INSERT,UPDATE DELETE

 

 

器工作原理

 

DML 器工作原理:

SQLServer 里,每个DML 器都定了两个特殊的表,一个是插入表

Inserted),一个是除表(Deleted)。两个表是建在数据器的内存中的,是由系管理的逻辑表,而不是真正存在数据中的物理表。两个表,用取的限,没有修改的限。两个表的构与触器所在数据表的构是完全一致的,当触器的工作完成之后,两个表也将会从内存中除。

 

插入表里存放的是更新前的记录于插入记录操作来,插入表里存放的是要插

入的数据;于更新记录操作来,插入表里存放的是要更新的记录

除表里存放的是更新后的记录于更新记录操作来除表里存放的是更新

前的记录(更新完后即被除);记录操作来除表里存入的是被除的记录

.After 器的工作原理

After器是在记录变更完之后才被激活行的。以记录为例:当SQL

Server接收到一个要除操作的SQL SQL Server 先将要除的记录放在除表里,然后把数据表里的记录删除,再激活After 器,After里的SQL 句。行完之后,除内存中的除表,退出整个操作。

 

DEMO:存表里,如果要除一条记录,在记录时,触器可以检查该产存数量是否零,如果不取消除操作。看一下数据是怎么操作的:

1)接收SQL 句,将要从存表里除的记录取出来,放在除表里。

2)从存表里该产记录

3)从除表里该产品的存数量字段,判断是不是零,如果零的

完成操作,从内存里清除除表;如果不零的,用RollbackTransaction 句来回操作。

2 InsteadOf 器的工作原理

InsteadOf 器与After 器不同。After 器是在InsertUpdateDelete

操作完成后才激活的,而Instead Of 器,是在些操作行之前就激活了,并且不再去行原来的SQL 操作,而去运行触器本身的SQL 句。

 

 

设计DML 器的注意事及技巧

设计器的限制

在触器中,有一些SQL 句是不能使用的,句包括:不能使用的句功

 

Alter Database 修改数据

Create Database 新建数据

Drop Database 除数据

Load Database 入数据

Load Log 入日志

Reconfigure 更新配置选项

Restore Database 原数据

Restore Log 原数据日志

另外,在操作的目的表或视图使用了下面的SQL ,不允DML器里再使用句:

INSERT, UPDATE,或者DELETE

器在另一表上INSERT,UPDATE 或者DELETE

不能使用的句功能

Create Index 建立索引

Alter Index 修改索引

Drop Index 除索引

DBCC Dbreindex 重新生成索引

Alter Partition Function 拆分或合并更改分区

Drop Table 除数据表

Alter Table 修改数据表

 

如何在触器取得字段修改前和修改后的数据

之前介绍过SQL Server 每个触器都定了两个虚表,一个是插入表

inserted),一个是除表(deleted),在把两个表存放的数据列表明一下:

激活触器的Inserted Deleted

Insert 存放要插入的记录

Update 存放要更新的记录 存放更新前的旧记录

Delete 存放要除的旧记录

以上面记录为例,在器要判断存数量是否零,那么判断应该这么写:

If(Select 存数量From Deleted)>0

Begin

Print存数量大于零不能除此记录

RollbackTransaction

End

其它注意事

After 器只能用于数据表中,Instead Of 器可以用于数据表和视图上,但两种器都不可以建立在临时表上。

一个数据表可以有多个触器,但是一个触器只能对应一个表。

在同一个数据表中,每个操作(如InsertUpdateDelete)而言可以建立多个After ,但Instead Of 针对每个操作只有建立一个。

如果针对某个操作即置了After器又置了Instead Of 器,那么Instead of器一定会激活,而After 器就不一定会激活了。

Truncate Table 似于Delete 句可以记录,但是它不能激活Delete型的触器。因Truncate Table 句是不日志的。

WRITETEXT 句不能触Insert Update 型的触器。

不同的SQL 句,可以触同一个触器,如Insert Update句都可以激活同一个触器。

 

ALTER

法:

CREATETRIGGER <Schema_Name, sysname, Schema_Name>.<Trigger_Name, sysname,

Trigger_Name>

ON <Schema_Name, sysname, Schema_Name>.<Table_Name, sysname, Table_Name>

AFTER<Data_Modification_Statements, , INSERT,DELETE,UPDATE>

AS

BEGIN

--SET NOCOUNT ON added to prevent extra result sets from

--interfering with SELECT statements.

SETNOCOUNT ON;

--Insert statements for trigger here

END

GO

转换成中文:

CREATETRIGGER 器名

ON 数据表名或视图

AFTERINSERTDELETEUPDATE

AS

BEGIN

--里是要运行的SQL

END

GO

参数明:

CREATE TRIGGER 器名:一句声明SQL 句是用来建立一个触器。其中触器名在所在的数据里必是唯一的。由于触器是建立中数据表或视图的,所以有很多人都 以只要是在不同的数据表中,触器的名称就可以相同,其器的全名(Server.Database.Owner.TriggerName)是必 唯一的,与触器在哪个数据表或视图无关。

ON 数据表名或视图名:是指定触器所在的数据表或视图,但是注意,只有Instead Of 器才能建立在视图上。并且,有With Check Option 视图也不允建立InsteadOf 器。

AFTER INSERT DELETEUPDATE是指定触器的型,是After Insert器,AfterDelete 器,或者是After Update 器。其中After 可以用For 来代取,它的意思都是一的,代表只有在数据表的操作都已正确完成后才会激活的触器。INSERTDELETEUPDATE 至少要指定一个,当然也可以指定多个,若指定多个,必用逗号来分开。其序可以任意放。

With EncryptionWithEncryption 是用来加密触器的,放“On 数据表名或视图的后面,“For”的前面。如果使用了器将会被加密,任何人都看不到触器的内容了。

DEMO

1建一个insert

--看原表数据:

use demo_db

go

select * from orders

--1建一个构与orders的空白测试ordermail,

select *

into ordermail

from orders

where 1=2

--2建一个触器,当插入一条数据,从inserted临时表)中插入一条数据到ordersmail表中

create trigger tr_sendordmail

on orders

forinsert

as

insert into ordermail

select * from inserted

go

--3、插入一条数据:

insert into orders

select 'a01','2011-09-04','cisco','CH','5000'

--4看触发结果:

select * from ordermail

分析:

insert 插入句,向表中插入数据行;

insert 器,向系统临时inserted 表中插入新行的份(副本)

检查inserted 表中插入的新行数据,生一个触操作,向表ordermail 中写入一行数据

2建一个DELETE

--1建一个触器,当除一条数据,插入一条数据到ordersmial

create trigger tr_sendordmaila

on orders

for delete

as

insert into ordermail

select * from deleted

go

--2除数据:

delete Orders

where cust='cisco'

--3、看触发结果:

select * from ordermail

select * from Orders

分析:

delete 句,除表中的数据行;

delete 除触器,向系统临时表的deleted 表中插入被除的副本

检查deleted 表中被除的数据,生一个触操作,向表ordermail 中写入一行数据

3建一个UPDATE

--除表ordermial中的数据

delete ordermail

where docno='a01'

select * from ordermail

比在使用UPDATE ,从inserteddeleted 表插入数据

在使用UPDATE,从inserted插入数据

--1建触器,当表orders行一个update操作,触操作从inserted表中插入数据到ordermail

create trigger tr_sendordmaild

on orders

for update

as

insert into ordermail

select * from inserted

go

--2、更新一条数据

update Orders set cust ='linkcom'

go

--3看触发结

select * from ordermail

select * from Orders

返回果:

从上可以看到,表ordermail 中插入的数据是upadate 后的数据

在使用UPDATE ,从deleted 插入数据

--1建触器,当表orders行一个update操作,触操作从deleted表中插入数据到ordermail

create trigger tr_sendordmaile

on orders

for update

as

insert into ordermail

select * from deleted

go

--2、更新一条数据

update Orders set cust ='cisco'

go

--3看触发结

select * from ordermail

select *  from Orders

返回:

从上可以看出,表ordermail 中插入的数据是update 前及update后的数据

4建一个列UPDATE 器,当列新某一列,触某一

--除之前建的触

drop trigger tr_sendordmail

go

drop trigger tr_sendordmaila

go

drop trigger tr_sendordmaild

go

drop trigger tr_sendordmaile

go

--清空表ordermial 中的数据

delete ordermail

where cust in ('cisco','linkcom')

--1建一个触器,当列新表orders cust ,触一个操作,从deleted 表中插入数据到order mail表中

create trigger tr_sendordmail

on orders

for update

as

if update (cust)

begin

insert into ordermail

select * from inserted

end

go

--2、同更新2 条数据,docno 及列cust 行更新

update Orders

set docno = 'a01'

where docno = 'p02'

update Orders

set cust ='MOF'

where docno = 'a01'

go

--3看触发结果:

select * from ordermail

select * from Orders

可以看出,以上同时对docnocust 行更新,但只有更新列cust ,才触一条插入操作.

5、当更新某一列某个字段某个值时一个条件,插入ordersmail 一条数据

--1建触器,当列新表orders中列cust中字段值为aaa,触器,行一条插入操作

alter trigger tr_sendordmail

on orders

for update

as

if update (cust)

begin

if exists (select top 1 1 from inserted where cust ='aaa')

begin

insert into ordermail

select * from inserted

end

end

go

--2、同更新2 条数据,cust 行更新

update Orders

set cust ='mod'

where docno = 'p03'

go

update Orders

set cust ='aaa'

where docno = 'p03'

go

--3看触发结果:

select * from ordermail

select * from Orders

可以看出,以上同时对cust2 条数据更新,但只有更新列cust 值为aaa ,才触行一条插入操作.



简单实例: DML触发器之Insert

 

--判断如果存在表,删除

Use tempdb

If object_id('dbo.T1_Audit','U') IS NOT NULL  DROP TABLE dbo.T1_Audit;

If object_id('dbo.T1','U') IS NOT NULL DROP TABLE dbo.T1;

 

 

--建立两个测试表

CREATE TABLE dbo.T1

(

      keycol INT NOT NULL PRIMARY KEY,

      datacolvarchar(10) NOT NULL

);

 

CREATE TABLE dbo.T1_Audit

(

      Audit_lsn  INT NOT NULL IDENTITY PRIMARY KEY,

      Dt        datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),

    Login_name sysname NOT NULLDEFAULT(SUSER_SNAME()),

    Keycol int not null,

    Datacol VARCHAR(10)  NOT NULL

);

 

--创建INSERT触发器

CREATE TRIGGER trg_T1_INSERT_Audit ondbo.T1 AFTER INSERT

AS

SET NOCOUNT ON;

INSERT INTO dbo.T1_Audit(keycol,datacol)

Select keycol, datacol frominserted;

Go

 

--测试触发器是否触发

Insert into dbo.T1(keycol,datacol) values(200,'a');

Insert into dbo.T1(keycol,datacol) values(400,'x');

Insert into dbo.T1(keycol,datacol) values(500,'g');

 

--查询测试结果

Select audit_lsn, dt, login_name, keycol, datacol

From dbo.T1_Audit