我怎么知道触发器被触发了?

时间:2012-09-25 12:05:29

标签: sql-server sql-server-2008 triggers

我在Windows 7计算机上使用SQL Server 2008 R2。我有一个触发器应该在插入器上触发但不幸的是它没有。我没有SQL Profiler,因为我有快递版。有没有其他方法可以看出出了什么问题?表格团队的插入是使用SQL Server的导入向导完成的,我将.CSV导入到表格中。

CREATE TRIGGER teams.process ON teams
AFTER INSERT
AS
BEGIN
    DECLARE @homeTeamId INT
    DECLARE @awayTeamId INT
    DECLARE @maxTeamId INT
    DECLARE @matchId INT

    SELECT @maxTeamId = 0
    SELECT @maxTeamId = ISNULL(MAX(teamId), 0) from tblTeams

    --- Check if home team has already been inserted into the table.
    SELECT @homeTeamId = -1
    SELECT 
        @homeTeamId = teamId 
    FROM 
        tblTeams t
        JOIN inserted i
        ON t.teamName = i.hometeam
    IF (@homeTeamId = -1) 
    BEGIN
        SELECT @homeTeamId = @maxTeamId + 1
        SELECT @maxTeamId = @maxTeamId + 1
        INSERT INTO tblTeams SELECT @homeTeamId, i.hometeam FROM inserted i
    END

    --- Check if away team has already been inserted into the table.
    SELECT @awayTeamId = -1
    SELECT 
        @awayTeamId = teamId 
    FROM 
        tblTeams t
        JOIN inserted i
        ON t.teamName = i.awayteam
    IF (@awayTeamId = -1) 
    BEGIN
        SELECT @awayTeamId = @maxTeamId + 1
        SELECT @maxTeamId = @maxTeamId + 1
        INSERT INTO tblTeams SELECT @awayTeamId, i.awayteam FROM inserted i
    END

    -- insert a record into the matches table with the home team ID and away team ID.
    SELECT @matchId = 0
    SELECT @matchId = ISNULL(MAX(MatchId), 0) FROM tblMatches
    INSERT INTO tblMatches 
    SELECT @matchId + 1, @homeTeamId, @awayTeamId, i.score 
    FROM inserted i
END 

2 个答案:

答案 0 :(得分:1)

好。如果我们可以稍微更改tblTeamstblMatches的表定义,以便他们使用ID维护自己的IDENTITY列,那么我们可以修复触发器以确保安全多行插入:

create table teams (
    hometeam varchar(10) not null,
    awayteam varchar(10) not null,
    score int not null
)
create table tblteams (
    teamId int IDENTITY(1,1) not null,
    teamName varchar(10) not null
)
create table tblmatches (
    matchId int IDENTITY(1,1) not null,
    HomeTeamID int not null,
    AwayTeamID int not null,
    Score int not null
)
go
CREATE TRIGGER process ON teams
AFTER INSERT
AS
SET NOCOUNT ON
declare @TeamIDs table (TeamID int not null,TeamName varchar(10) not null)

;with AllTeams as (
    select hometeam as teamName from inserted
    union
    select awayteam from inserted
)
merge into tblTeams tt using AllTeams at on tt.teamName = at.teamName
when matched then update set teamName = at.teamName
when not matched then insert (teamName) values (at.teamName)
output inserted.TeamID,inserted.teamName into @TeamIDs;

insert into tblmatches (HomeTeamID,AwayTeamID,Score)
select ht.TeamID,at.TeamID,i.Score
from inserted i
inner join @TeamIDs ht on i.hometeam = ht.TeamName
inner join @TeamIDs at on i.awayteam = at.TeamName
GO

然后我们测试出来:

insert into teams (hometeam,awayteam,score) values
('abc','def',10),
('def','ghi',5),
('jkl','mno',7)
go
insert into teams (hometeam,awayteam,score) values
('abc','ghi',19),
('pqr','stu',11)
go
select * from tblteams
select * from tblmatches

现有触发器的问题是它无法处理包含多行的inserted - 触发器每语句触发一次,而不是每行触发一次。所以例如这些行是错误的:

SELECT @homeTeamId = @maxTeamId + 1
    SELECT @maxTeamId = @maxTeamId + 1
    INSERT INTO tblTeams SELECT @homeTeamId, i.hometeam FROM inserted i

因为可能有多个homeTeam值要处理。

它也没有很好地处理并发性 - 对并行发生的两次调用可能最终会与相同的 @maxTeamId值结束 - 然后尝试将行插入{{ 1}}具有相同的tblTeam值 - 而使用TeamId列时,SQL Server会自动为我们处理此问题。

上面唯一的轻微吝啬是使用IDENTITY插入新的小组 - MERGE行会为现有行执行No-Op WHEN MATCHED(因为我们知道{{ 1}}两边匹配),但这是一个很好的技巧,可以在一个语句中查找现有行和UPDATE个新行。


我刚刚意识到你说你正在使用导入数据向导。我觉得它生成的SSIS包使用Fast Load创建目的地,而不指定teamName。这也可能会打击你。

您可以使用向导生成程序包,然后编辑属性,或使用向导插入临时表,然后从该表中执行INSERT / FIRE_TRIGGERS到我们的{ {1}}表,然后让触发器触发。

答案 1 :(得分:1)

批量插入向导/数据导入向导通常会绕过目标表上的触发器。