今天周末,贴不多,就自己胡乱总结些技术问题吧,写得不好欢迎扔鸡蛋,不过最好扔熟的,晚饭没吃饱。
论坛上触发器的问题不少,而且很多触发器写得确实让人不敢恭维,包括一些被楼主认定正确的回答。
想先说说触发器的分类,当然不是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