触发器

一:什么是触发器
触发器是一种响应特定事件的特殊类型的存储过程
insert update... drop alter...等事件都有相应的触发器

二:简单的触发器
下面一个例子是在插入或者修改记录的时候的一个触发器
其中inserted表是一个临时表
存储的是将要插入的信息
这个触发器的目的是检查将要插入的信息是否符合规定
(在product表里没有特殊的记录)
这个例子是check约束所不能解决的了的

use AdventureWorks
go
create trigger orderDetailNotDiscontinued
    
on Sales.SalesOrderDetail
    after 
insertupdate
as
    
if exists
    (
        
select 'true' from Inserted i
        
join Production.Product p
        
on i.ProductID = p.ProductID
        
where p.DiscontinuedDate is not null
    )
    
begin
        
print('error appear.')
        
rollback tran
    
end
为了验证这个触发器
先给表加入一条不符合条件的记录
use AdventureWorks
go
update Production.Product
set DiscontinuedDate = getdate()
where ProductID = 680
好了现在来一条插入语句看看
use AdventureWorks
go
insert Sales.SalesOrderDetail
(SalesOrderID,OrderQty,ProductID,SpecialOfferID,UnitPrice,UnitPriceDiscount)
values
(
43660,5,680,1,1431,0)
得到的消息是:
error appear.
消息 3609,级别 16,状态 1,第 1 行
事务在触发器中结束。批处理已中止。

三:针对触发器的操作
1.禁用触发器
use AdventureWorks
go
alter table Sales.SalesOrderDetail
disable 
trigger all  --这里的all可以是具体的触发器名
2.删除触发器
use AdventureWorks
go
drop trigger orderDetailNotDiscontinued
3.修改触发器
use xland
go 
alter trigger tr_title
on mytable
for insertupdate
as
if update(title)
begin
    
print('title1')
end 
(这里的update()函数不懂没关系,下面会说到)

四:使用触发器记录操作情况
先看代码
use AdventureWorks
go
create table Production.inventoryAudit
(
    id 
int identity primary key,
    productid   
int   not null
    
references Production.Product(ProductID),
    netadjustment  
smallint not null,
    modifieddate  
datetime default(current_timestamp)    
)
go
create trigger ProductAudit
    
on Production.ProductInventory
    
for insert,update,delete
as
insert into Production.inventoryAudit
(productid,netadjustment)
select coalesce  --coalesce哪个不为空用哪个
(i.ProductID,d.ProductID),
isnull(i.Quantity,0- isnull(d.Quantity,0as netadjustmenu
from Inserted i
full join Deleted d
on i.ProductID = d.ProductID
and i.LocationID = d.LocationID
where 
isnull(i.Quantity,0- isnull(d.Quantity,0!=0
--isnull(i.Quantity,0)如果i.Quantity为空返回0(这个函数比较有用)
注意这里用了full  join
其实如果不是高并发inserted和deleted中有一个表是不存在的
下面来测试一下这个触发器
use AdventureWorks
go
update Production.ProductInventory
set Quantity = Quantity +7
where ProductID = 1
and LocationID = 50
select * from Production.inventoryAudit
来看看消息:
(1 行受影响)     这是修改的一行
(1 行受影响)     这是触发器执行的一行
(1 行受影响)     这是select的一行
五:视图上的触发器
instead of触发器
先创建一个视图
use xland
go
create view UserArticle_vw
with Schemabinding
as
select a.id,a.title,u.username
from dbo.mytable a  --必须有架构名,可以用as
join dbo.[user] u
on u.id = a.uid
检查该视图
use xland
go
select * from UserArticle_vw where id = 2
创建一个视图上的触发器
use xland
go
create trigger TRMytableInsert on UserArticle_vw
instead 
of insert 
as
begin
if (select count(*from inserted) >0
   
begin
     
insert into mytable
     
select i.title,u.id from inserted i
     
join [user] u
     
on u.username = i.username
     
if @@rowcount = 0 --返回受影响的行数
        print('error appear')  
   
end 
end
对这个视图执行插入操作!(有了上面的触发器就可以插入了)
use xland
go
insert into UserArticle_vw (title,username) values ('zhe shi title','xland')
看下消息
(1 行受影响)
(1 行受影响)
类似的还有
insted of update触发器
insted of delete触发器

六:触发器的相关函数
看这个触发器
use xland
go 
alter trigger tr_title
on mytable
for insertupdate
as
if update(title)
begin
    
print('title1')
end 
update()函数意思是
指定的列被更改时发生
看下验证语句
use xland
go 
update mytable set title = 'xland' where id = 7
结果
title1
(1 行受影响)
还有一个函数
columns_updated()有检查多个列的能力
比较高级,也比较少用  我在这里就不写了
上一篇:存储过程和用户自定义函数


下一篇:全文索引