程序人生,软件一生。

欢迎来到顾祥先的网站
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

触发器的分类

Posted on 2004-09-28 10:36  Guxx  阅读(2212)  评论(1编辑  收藏  举报

今天周末,贴不多,就自己胡乱总结些技术问题吧,写得不好欢迎扔鸡蛋,不过最好扔熟的,晚饭没吃饱。
    论坛上触发器的问题不少,而且很多触发器写得确实让人不敢恭维,包括一些被楼主认定正确的回答。
    想先说说触发器的分类,当然不是insert触发器、update触发器或者after触发器、instead of触发器这样的分类,而是试图从触发器的应用或者说触发器的功能上来分类。我觉得触发器可以分为以下类,各类的功能不同,写触发器注意的方面也应该不同。
    1、日志类触发器
    这类触发器的功能是记录对表的操作,从技术上来说,这类触发器最简单,因为不管是记录操作类别还是记录改前、删前数据,触发器都只需做插入操作,典型的贴子有:
http://community.csdn.net/Expert/topic/3243/3243457.xml?temp=.9883539
看起来复杂,但是难度不在触发器这一块。
http://community.csdn.net/Expert/topic/3049/3049973.xml?temp=.5422632
记录改前数据,简单吧?

     2、约束类触发器
     这是联机帮助推荐的触发器的使用方法,主要用于实现一些不能用约束来表示的业务规则,这类触发器有个共同特点是:都必须有判断是否违反规则,如果违反规则,抛出错误、回滚事务并返回的语句,典型的贴子有:
http://community.csdn.net/Expert/topic/3241/3241485.xml?temp=.9982263

     3、同步类触发器
     这类触发器论坛问的比较多,大部分是一个表的数据变化要同时在另一个表也变化,这类触发器应该比较好的理解inserted、deleted临时表,涉及的表一定要有主键,而且应该规定不允许修改主键,个人认为特别忌讳用游标(因为效率)和把临时表的数据取到变量(因为这样容易在一次更改多条记录的时候漏处理一些数据),典型的贴子有:
http://community.csdn.net/Expert/topic/3252/3252484.xml?temp=.1456873
一个表的修改反映到另一个表,搂主的错误其实是写update语句的错误。

http://community.csdn.net/Expert/topic/2861/2861142.xml?temp=5.314273E-02
一个表的变更要影响另一个表的变更,楼主的
if ( select Subject from inserted ) = '短期借款'
适合取到变量一样的,不能处理一次插入多条记录的情况。

     4、统计类触发器
     统计类触发器就是在插入、修改、删除一个表的数据的同时,把这个表的统计数据更新到另一个表,这类应用应该是比较复杂的,触发器不好调试,写这类触发器的时候尤其要小心,要考虑各种可能的情况。

这个例子的答案好像还有错误,至少不能只考虑update的情况
http://community.csdn.net/Expert/topic/3050/3050415.xml?temp=2.557635E-04

     5、综合类触发器
     大多是2、3、4类功能组合在一起,比如在进销存系统,进销表的触发器,实现修改库存表数据,同时约束库存不能负数,组合多类触发器功能的触发器。
(没找到贴子)
     
     6、特殊的触发器
     记得有个贴子,正牌邹建回答的,大意是在某个表插入数据后一定时间,要做某个动作,正牌邹建的解法使用触发器加job,job定时触发,可惜找半天没找到。

这个应该叫日志类吧
http://community.csdn.net/Expert/topic/3238/3238374.xml?temp=.2266657

这个应该是综合类吧
先进先出的还款处理触发器
http://blog.csdn.net/zjcxc/archive/2004/07/22/48722.aspx

这个应该叫特殊类吧
http://community.csdn.net/Expert/topic/3220/3220744.xml?temp=.8733637

 

--这是楼主提到的触发器+作业

/*--作业处理实例

 根据sendTab的SendTime定制作业
 并且在该作业完成时,可以自动删除作业
--*/

--示例

--测试表
create table sendTab(ID int identity(1,1),Name varchar(10)
 ,SendTime datetime,AcceptUnit varchar(10)
 ,SendUnit varchar(10),Content varchar(8000))

create table accepteTab(ID int identity(1,1),Name varchar(10)
 ,SendUnit varchar(10),AcceptUnit varchar(10),Content varchar(8000))
go

--创建处理的存储过程
create proc p_JobSet
@id int,   --要处理的sendTab的id
@is_delete bit=0 --是否仅删除,为0则否,为1则是
as
declare @dbname sysname,@jobname sysname
 ,@date int,@time int

select @jobname='定时发送作业_'+cast(@id as varchar)
 ,@date=convert(varchar,SendTime,112)
 ,@time=replace(convert(varchar,SendTime,108),':','')
from sendTab where id=@id

if exists(select 1 from msdb..sysjobs where name=@jobname)
 exec msdb..sp_delete_job @job_name=@jobname

if @is_delete=1 return

--创建作业
exec msdb..sp_add_job @job_name=@jobname,@delete_level=1

--创建作业步骤
declare @sql varchar(800)
select @sql='insert accepteTab(name,SendUnit,AcceptUnit,Content)
  select name,AcceptUnit,SendUnit,Content from sendTab where id='
  +cast(@id as varchar)
 ,@dbname=db_name()

exec msdb..sp_add_jobstep @job_name=@jobname,
 @step_name = '发送处理步骤',
 @subsystem = 'TSQL',
 @database_name=@dbname,
 @command = @sql,
 @retry_attempts = 5,   --重试次数
 @retry_interval = 5    --重试间隔

--创建调度
EXEC msdb..sp_add_jobschedule @job_name = @jobname,
 @name = '时间安排',
 @enabled = 1,
 @freq_type = 1,
 @active_start_date = @date,
 @active_start_time = @time

-- 添加目标服务器
EXEC msdb.dbo.sp_add_jobserver
 @job_name = @jobname ,
 @server_name = N'(local)'
go

--创建处理的触发器(新增/修改)
create trigger tr_insert_update on sendTab
for insert,update
as
declare @id int
declare tb cursor local for select id from inserted
open tb
fetch next from tb into @id
while @@fetch_status=0
begin
 exec p_JobSet @id
 fetch next from tb into @id
end
close tb
deallocate tb
go

--创建处理的触发器(删除)
create trigger tr_delete on sendTab
for delete
as
declare @id int
declare tb cursor local for select id from deleted
open tb
fetch next from tb into @id
while @@fetch_status=0
begin
 exec p_JobSet @id,1
 fetch next from tb into @id
end
close tb
deallocate tb
go

--测试

--插入数据
insert sendTab
select '文书1','2004/5/1 12:00:00','UnitA','UnitB','txt'
union all select '文书2','2004/5/12 12:00:00','UnitA','UnitB','txt'
union all select '文书3','2004/5/21 12:00:00','UnitA','UnitB','txt'

--修改
update sendTab set name='档案1',SendTime='2004/5/1 15:00:00'
where id=1

--删除
delete sendtab where id=3
go
--删除测试
drop table sendTab,accepteTab
drop proc p_JobSet