O seguinte gatilho que une a tabela Inserted em si cria vários registros indesejados:
CREATE TRIGGER [dbo].[trFooInsert] on [dbo].[Foo]
AFTER INSERT
AS
BEGIN
IF EXISTS(SELECT 1 FROM Inserted a
LEFT JOIN Inserted b ON b.Flag = 1 AND a.ID = b.ID
WHERE b.Flag IS NULL AND a.Flag = 0
) -- exists
BEGIN
INSERT INTO Foo(ID, Etc, Flag)
SELECT a.ID, a.Etc, 1 FROM Inserted a
LEFT JOIN Inserted b ON b.Flag = 1 AND a.ID = b.ID
WHERE b.Flag IS NULL AND a.Flag = 0
END -- insert
END -- trigger
Onde como este gatilho que se junta a Inserted on Foo (a tabela à qual o gatilho está vinculado) cria um registro.
CREATE TRIGGER [dbo].[trFooInsert] on [dbo].[Foo]
AFTER INSERT
AS
BEGIN
IF EXISTS(SELECT 1 FROM Inserted a
LEFT JOIN Foo b ON b.Flag = 1 AND a.ID = b.ID
WHERE b.Flag IS NULL AND a.Flag = 0
) -- exists
BEGIN
INSERT INTO Foo(ID, Etc, Flag)
SELECT a.ID, a.Etc, 1 FROM Inserted a
LEFT JOIN Foo b ON b.Flag = 1 AND a.ID = b.ID
WHERE b.Flag IS NULL AND a.Flag = 0
END -- insert
END -- trigger
O segundo gatilho faz exatamente o que eu quero, mas estou tentando entender porque o primeiro gatilho cria tantos registros. Eu esperava que Inserted e Foo fossem idênticos quando o gatilho fosse acionado. Existe algum tipo de propriedade/comportamento especial que a tabela Inserted exibe ao se unir a si mesma?
Desculpas se não houver informações suficientes, tentei reduzir às diferenças básicas entre os dois gatilhos.
Atualização nº 1
Estou tentando preencher a tabela com registros em que a conta do usuário possui transações, mas não possui o sinalizador definido.
Atualização nº 2
As inserções são realizadas por um aplicativo C#. A fonte de dados é um arquivo simples em que cada linha representa uma única linha na tabela. Não sei se o aplicativo usa pool de conexões ou se isso é importante. As inserções em massa são feitas uma vez por mês. O aplicativo C# geralmente importa 8373 linhas. O primeiro gatilho insere 50 linhas adicionais, há apenas uma linha que eu quero.
Primeiro, você não precisa da
IF EXISTS
parte em seu código de gatilho. Você tem exatamente o mesmo código na segunda parte, portanto, se houver 0 linhas produzidas, você inserirá 0 linhas de qualquer maneira:que também pode ser escrita como:
Portanto, você deseja que qualquer inserção na tabela com
Flag=0
também acione outra inserção, com os mesmos dados, masFlag=1
(a menos que já exista uma linhaFoo
com issoID
eFlag=1
.Em segundo lugar, e do que se trata o problema real,
Inserted
é uma tabela especial com todas as (apenas) linhas "inseridas", não a tabela completa na qual você inseriu. Obviamente, tem menos (ou igual) linhasFoo
após a inserção. Portanto, uma junção a ele não fornecerá os mesmos resultados que uma junção aFoo
.O gatilho que produz as várias linhas indesejadas tinha
Inserted b
em vezFoo b
disso:Para qualquer inserção na tabela com
Flag=0
ela também acionou outra inserção, com os mesmos dados, masFlag=1
(a menos que esta mesma inserção tenha essa linha inserida).Você pode ler mais sobre o especial
Inserted
e asDeleted
tabelas no MSDN:Como usar as tabelas inseridas e excluídas