删除后触发执行顺序

Car*_*ose 0 trigger sql-server delete sql-server-2016

假设我有两张表,一张名为ParentTable,另一张名为ChildTable,具有一对多关系,其中一个父项可能有多个子项。

我正在创建一个AFTER DELETE触发器ChildTable。在该触发器中,我正在检查一个值ParentTable(如果存在),如下所示:

-- ...
FROM deleted d
JOIN ParentTable pt ON d.FK_Parent = pt.ID
WHERE pt.Foo = 'bar'
Run Code Online (Sandbox Code Playgroud)
  1. 如果我先从 删除ChildTable,然后从 删除ParentTableAFTER DELETE触发器是在删除行之前还是之后ParentTable触发?

    A。这两个DELETE语句通常位于显式事务中,因为我使用的是实体框架。

  2. 如果我将外键设置为ChildTableCASCADE DELETE然后从ParentTableonly 中删除,当触发器触发时,中的行ParentTable仍然可以访问吗AFTER DELETE

Cha*_*ace 7

来自文档:

AFTER 触发器仅在触发 SQL 语句成功运行后运行。此成功执行包括与更新或删除的对象关联的所有引用级联操作和约束检查。

  1. 首先删除ChildTable,然后从 删除ParentTable,将始终在父触发器之前执行子触发器,因为触发器是按语句触发的,而不是按事务或批处理触发的。

  2. 您可以很容易地测试级联外键。

CREATE TABLE Parent (id int identity PRIMARY KEY);
CREATE TABLE Child (id int identity PRIMARY KEY, pId int REFERENCES Parent(id) ON DELETE CASCADE);
Run Code Online (Sandbox Code Playgroud)
CREATE TRIGGER trParent ON Parent AFTER DELETE AS

PRINT 'trParent';
DECLARE @i int;
SELECT @i = COUNT(*) FROM Parent;
PRINT @i;
SELECT @i = COUNT(*) FROM Child;
PRINT @i;
Run Code Online (Sandbox Code Playgroud)
CREATE TRIGGER trChild ON Child AFTER DELETE AS

PRINT 'trChild';
DECLARE @i int;
SELECT @i = COUNT(*) FROM Parent;
PRINT @i;
SELECT @i = COUNT(*) FROM Child;
PRINT @i;
Run Code Online (Sandbox Code Playgroud)
INSERT Parent DEFAULT VALUES;
INSERT Child(pId) VALUES (SCOPE_IDENTITY());
DELETE Parent;
Run Code Online (Sandbox Code Playgroud)

数据库<>小提琴

这打印

trChild
0
0
trParent
0
0
Run Code Online (Sandbox Code Playgroud)

所以Child先触发触发器,然后再Parent触发触发器。但是在调用第一个触发器之前,两个表中都没有行。要访问原始数据,您可以使用deleted触发器中的表。

请注意,如果没有要级联的行,则子触发器似乎根本不会触发