以下将Inserted表连接到自身的触发器会创建多个不需要的记录:
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
在哪里加入Inserted on Foo的这个触发器(触发器链接到的表)会创建一条记录。
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
第二个触发器完全符合我的要求,但我正在尝试为什么第一个触发器会创建这么多记录。当触发器触发时,我希望Inserted和Foo是相同的。插入的表在加入自身时是否有任何类型的特殊属性/行为。
抱歉,如果没有足够的信息,我试图减少两个触发器之间的基本差异。
更新#1
我正在尝试用用户帐户有交易但没有设置标志的记录来回填表格。
更新#2
插入由 C# 应用程序执行。数据源是平面文件,其中每一行代表表中的一行。我不知道应用程序是否使用连接池或者这是否重要。批量插入每月进行一次。C# 应用程序通常导入 8373 行。第一个触发器插入 50 个额外的行,我只想要一行。
首先,您不需要
IF EXISTS
触发代码中的部分。您在第二部分中具有完全相同的代码,因此如果生成了 0 行,则无论如何您将插入 0 行:也可以写成:
因此,您希望表上的任何插入
Flag=0
也触发另一个插入,具有相同的数据但是Flag=1
(除非已经有一行Foo
与.ID
Flag=1
其次,实际问题是关于
Inserted
一个特殊表,其中包含所有(仅)“插入”行,而不是您插入的完整表。Foo
它显然在插入之后具有少于(或等于)的行。所以加入它不会给出与加入相同的结果Foo
。产生多个不需要的行的触发器有
Inserted b
而不是Foo b
这样做:对于带有它的表上的任何插入,
Flag=0
它也触发了另一个插入,具有相同的数据,但是Flag=1
(除非同一个插入插入了这样的行)。您可以在 MSDN中阅读有关特殊表
Inserted
和表的更多信息:如何使用插入和删除的表Deleted