编写复杂的触发器
Posted
技术标签:
【中文标题】编写复杂的触发器【英文标题】:Writing a complex trigger 【发布时间】:2009-10-20 20:42:58 【问题描述】:我正在使用 SQL Server 2000。我正在编写一个触发器,该触发器在字段申请者.AppStatusRowID 时执行
表申请者链接到表 Location、表 Company 和表 AppStatus。
我的问题是在我的查询中创建连接。
当申请人.AppStatusRowID 更新时,我想从中获取值 申请人.AppStatusRowID、申请人.FirstName、申请人.姓氏、Location.LocNumber、Location.LocationName、Company.CompanyCode、AppStatus.DisplayText
连接将是:
Select * from Applicant A
Inner Join AppStatus ast on ast.RowID = a.AppStatusRowID
Inner Join Location l on l.RowID = a.LocationRowID
Inner Join Company c on c.RowID = l.CompanyRowID
这将被插入到审核表中(字段为申请人 ID、姓氏、名字、日期、时间、公司、位置编号、位置名称、状态处置、用户)
我的问题是查询内连接...
【问题讨论】:
我希望你不要更新主键,这是个坏主意。 如果您更新密钥,您如何加入其他表? ast.RowID = a.AppStatusRowID 【参考方案1】:首先让我们向您介绍仅在触发器中可用的插入和删除伪表。 Inserted 有新值,delted 有旧值或正在删除的记录。
您不想只将所有记录插入到您的审计表中。
因此,要插入审计表,您可能需要在触发器代码中添加类似内容:
insert Myaudittable (<insert field list here>)
Select <insert field list here> from Inserted i
Inner Join AppStatus ast on ast.RowID = i.AppStatusRowID
Inner Join Location l on l.RowID = i.LocationRowID
Inner Join Company c on c.RowID = l.CompanyRowID
我会亲自添加新旧值的列、更改类型的列、更改的日期以及进行更改的用户,但您肯定有自己的要求要遵循。
建议您阅读在线图书中有关触发器的内容,因为它们可能很难正确处理。
这是我经常使用的一种测试和调试触发器的方法。首先,我创建了名为#delted 和#inserted 的临时表,它们具有我将要放置触发器的表的结构。然后我编写代码来使用那些而不是删除或插入的表。这样我就可以边看边看,确保一切都正确,然后再将代码更改为触发器。下面的示例添加了您的代码并稍作修改:
Create table #inserted(Rowid int, lastname varchar(100), firstname varchar(100), appstatusRowid int)
Insert #inserted
select 1, 'Jones', 'Ed', 30
union all
select 2, 'Smith', 'Betty', 20
Create table #deleted (Rowid int, lastname varchar(100), firstname varchar(100), appstatusRowid int)
Insert #deleted
select 1, 'Jones', 'Ed', 10
union all
select 2, 'Smith', 'Betty', 20
--CREATE TRIGGER tri_UpdateAppDisp ON dbo.Test_App
--For Update
--AS
--If Update(appstatusrowid)
IF exists (select i.appstatusRowid from #inserted i join #deleted d on i.rowid = d.rowid
Where d.appstatusrowid <> i.appstatusrowid)
BEGIN
--Insert AppDisp(AppID, LastName, FirstName, [DateTime],Company,Location,LocationName, StatusDisp,[Username])
Select d.Rowid,d.LastName, d.FirstName, getDate(),C.CompanyCode,
l.locnum,l.locname, ast.Displaytext, SUSER_SNAME()+' '+User
From #deleted d
Join #inserted i on i.rowid = d.rowid
--From deleted d
--Join inserted i on i.rowid = d.rowid
Inner join Test_App a with (nolock) on a.RowID = d.rowid
inner join location l with (nolock) on l.rowid = d.Locationrowid
inner join appstatus ast with (nolock) on ast.rowid = d.appstatusrowid
inner join company c with (nolock) on c.rowid = l.CompanyRowid
Where d.appstatusrowid <> i.appstatusrowid)
end
一旦你得到正确的选择数据,那么很容易取消注释掉触发代码和插入行并将#deleted或#inserted更改为删除或插入。
您会注意到我在临时表中有两条记录,一条满足您的条件,一条不满足。这允许您测试多个记录更新以及满足条件和不满足条件的结果。应该编写所有触发器来处理多条记录,因为它们不是逐行触发,而是按批次触发。
【讨论】:
不幸的是,我的创意有限。一旦有人更新了申请人表中的 AppStatusRowID,我需要将记录插入到审计表中。因此需要触发器。但我无法让我的联接查询工作。 那么你可能不得不使用 AppStatusRowID 的旧值,即参考 DELETED(而不是上面代码中的 Inserted)。 我尝试了 DELETED,但仍然没有为我工作。目标表未更新。 我一回到我的电脑就会发布它。 CREATE TRIGGER tri_UpdateAppDisp ON dbo.Test_App For Update AS If Update(appstatusrowid) BEGIN Insert AppDisp(AppID, LastName, FirstName, [DateTime],Company,Location,LocationName, StatusDisp,[Username]) 选择d.Rowid,d.LastName, d.FirstName, getDate(),C.CompanyCode,l.locnum,l.locname, ast.Displaytext, SUSER_SNAME()+' '+User From deleted d with(nolock) 内联Test_App a with (nolock) on a.RowID = d.rowid 内部连接位置 l with (nolock) on l.rowid = d.Locationrowid 内部连接 appstatus ast with (nolock) on ast.rowid = d.appstatusrowid以上是关于编写复杂的触发器的主要内容,如果未能解决你的问题,请参考以下文章