小心触发器脚本陷阱
1,含有bug的SQL
笔者在使用MSSQLServer 2008数据库时,需要在某表tableA上建立触发器,于是写了如下SQL:
create TRIGGER [tr_parking_ins2] ON [tableA] AFTER insert AS BEGIN declare @CPLX varchar(20) select @CPLX ='' select @CPLX = b.value from inserted a, GT b where b.app=1 and a.[plate]=b.name and b.updateTime> getDate()- 10.0/60/24 if @CPLX <>'' begin update [tableA] set CPLX=@CPLX from inserted a, [tableA] b where a.id= b.id end END INSERT INTO [dbo].[GT]([app], [name], [value]) VALUES ('9', 'upTrig20200331', 'tr_parking_ins2');
上述触发器主要目的是,每当tableA表插入一条记录时,就从GT表中查找对应的CPLX(车牌类型),进行更新
最后一条语句的目的是,向GT表插入一条标记,表明该数据库已建立了tr_tableA_ins触发器。
2,bug发威
后来,在一段时间内程序运行正常。但后来发现越来越慢。
查看数据库表GT,发现其中充满了大量的重复的记录。如下图所示:
这些重复记录以 ('9', 'upTrig20200331', 'tr_parking_ins2')为特征,经跟踪分析,发现是每在tableA中插入一条记录,就会往GT表插入一条这样的数据。
3,bug分析
显然,上述现象表明,下面这条语句已经成为了tr_parking_ins2 触发器的一部分:
INSERT INTO [dbo].[GT]([app], [name], [value]) VALUES ('9', 'upTrig20200331', 'tr_parking_ins2');
但我明明是将上述语句写在 触发器创建语句的begin/end以外的啊,难道begin/end以外的语句也是触发器的一部分?
答案是,确实是的。虽然有点意外,但也不难理解。因为DDL 类型的SQL语句,以碰到GO,或另外一条DDL语句为结束。
哈哈,一不小心就写了bug!
因此,前面的触发器创建语句应该按如下写法,方为妥当:
create TRIGGER [tr_parking_ins2] ON [tableA] AFTER insert AS BEGIN declare @CPLX varchar(20) select @CPLX ='' select @CPLX = b.value from inserted a, GT b where b.app=1 and a.[plate]=b.name and b.updateTime> getDate()- 10.0/60/24 if @CPLX <>'' begin update [tableA] set CPLX=@CPLX from inserted a, [tableA] b where a.id= b.id end END go --重要!! INSERT INTO [dbo].[GT]([app], [name], [value]) VALUES ('9', 'upTrig20200331', 'tr_parking_ins2');