2

Windows 7 マシンで SQL Server 2008 R2 を使用しています。挿入で起動する必要があるトリガーがありますが、残念ながらそうではありません。Express Edition を使用しているため、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 
4

2 に答える 2

1

一括挿入ウィザード/データインポートウィザードは通常、宛先テーブルのトリガーをバイパスします。

于 2012-09-25T13:06:57.280 に答える
1

わかった。と のテーブル定義を少し変更して、 を使用して独自の列を維持できる場合はtblTeamstblMatches複数IDIDENTITYの挿入に対して安全になるようにトリガーを修正できます。

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複数の行を含むことに対応していないことです。トリガーは、行ごとではなく、ステートメントごとに 1 回起動ます。たとえば、これらの行は間違っています:

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

homeTeam扱う値が複数ある可能性があるためです。

また、同時実行性もうまく処理できませんでした。並行して発生するトリガーへの 2 つの呼び出しが同じ値になる可能性があり 、その後、同じ値で@maxTeamId行を挿入しようとしますが、列を使用すると、SQL Server はこれを自動的に処理します。 .tblTeamTeamIdIDENTITY

上記のほんのわずかな間違いは、MERGE新しいチームを挿入するために使用されていることです。行は既存の行に対してWHEN MATCHEDノーオペレーションを実行します (両側で一致するUPDATEことがわかっているため)。ただし、既存の行と単一のステートメントで新しい行。teamNameINSERT


データのインポート ウィザードを使用しているとのことでした。それが生成する SSIS パッケージは、Fast Loadを使用して宛先を作成し、指定していない気がしますFIRE_TRIGGERS。それはあなたも台無しにする可能性があります。

ウィザードを使用してパッケージを生成してからプロパティを編集するか、ウィザードを使用してステージング テーブルに挿入し、そのテーブルからテーブルに単純なINSERT/を実行して、トリガーをそのように起動させることができます。SELECTteams

于 2012-09-25T12:49:34.937 に答える