sql-server - 我如何知道触发器是否被触发?

标签 sql-server sql-server-2008 triggers

我在 Windows 7 计算机上使用 SQL Server 2008 R2。我有一个应该在插入件上触发的触发器,但不幸的是它没有。我没有 SQL Profiler,因为我有 Express 版本。还有其他方法可以查看出了什么问题吗?向表 team 的插入是通过 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 

最佳答案

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

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 值 - 然后尝试插入将具有相同 TeamId 值的行放入 tblTeam 中 - 而使用 IDENTITY 列,SQL Server 会自动为我们处理此问题。

上面唯一的小改动是使用 MERGE 插入新团队 - WHEN MATCHED 行将执行 No-Op UPDATE对于现有行(因为我们知道 teamName 两边都匹配),但在单个语句中查找现有行和 INSERT 新行是一个很好的技巧.


我刚刚意识到您说过您正在使用导入数据向导。我有一种感觉,它生成的 SSIS 包使用 Fast Load 创建目标,并且未指定 FIRE_TRIGGERS。这也可能会毁掉你。

您可以使用向导生成包,然后编辑属性,或者使用向导插入到临时表中,然后执行简单的 INSERT/SELECT从该表进入我们的 teams 表,然后让触发器以这种方式触发。

关于sql-server - 我如何知道触发器是否被触发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12582615/

相关文章:

sql-server - SQL Server Management Studio 的 Mac 替代品?

sql-server - 如何替换ssis包中的unicode字符

sql - 修复运行缓慢的SQL查询

sql - 仅通过月份名称获取月份编号

MySQL 触发器。如何在有限的时间内存储表中的每一行数据?

MySQL 表示 : #1336 - Dynamic SQL is not allowed in stored function or trigger

perl - 驼鹿触发调用者

mysql - nvarchar 持有 "integer"值 - 转换时不报告错误 - SQL 注入(inject)

sql-server - 是否可以在单个分区上运行 DBCC CHECKDB?

具有最高优先级的 SQLrange 查询