小心触发器脚本陷阱

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');
原文地址:https://www.cnblogs.com/jackkwok/p/15589458.html