如何在SQL Server内部级联更新/删除?

Man*_*wat 4 sql-server triggers

好的,我认为问题不明确.在这里,我以其他方式重写这一点.

假设我创建了两个表,

  • table1(c1 int PRIMARY KEY)

  • table2(table1c11 int)

有之间的关系table1,并table2table1.c1=table2.table1c11

并且,我在table1和中执行以下语句table2

insert into table1(c1)
values('a'),('b'),('c'),('d'),('e')

insert into table2(table1c11)
values('a'),('a'),('b'),('d')
Run Code Online (Sandbox Code Playgroud)

现在我想要实现的是,一旦我更新的值c1table1相应的数据table2就会自动改变.为此,我需要在table1table2关系中创建约束并应用CASCADE UPDATE.

所以,稍后我在table1ie中应用一个新的SQL更新语句

Update table1 set c1=c1+'updated'
Run Code Online (Sandbox Code Playgroud)

然后数据table2也会改变,但是如果我想通过实现相同的功能INSTEAD OF UPDATE TRIGGER,那么我需要编写而不是更新触发器,在里面,我需要处理两个魔术表INSERTEDDELETED.

但重点是,在这种情况下,我只有一个列存在table1,我正在更新同一列,所以我怎么能映射插入和删除的行.如果我使用CASCADing,SQL Server也会做同样的事情.

因此,问题出现了SQL Server如何在表中的主键数据更改的情况下处理批量更新.

Mik*_*son 12

因此,问题出现了SQL Server如何在表中的主键数据更改的情况下处理批量更新.

SQL Server为更新两个表的update语句构建查询计划.

创建表:

create table T1
(
  T1ID int primary key
);

create table T2
(
  T2ID int primary key, 
  T1ID int references T1(T1ID) on update cascade
)
Run Code Online (Sandbox Code Playgroud)

添加一些数据:

insert into T1 values(1), (2)
insert into T2 values(1, 1), (2, 1), (3, 2)
Run Code Online (Sandbox Code Playgroud)

更新主键T1:

update T1
set T1.T1ID = 3
where T1.T1ID = 1
Run Code Online (Sandbox Code Playgroud)

更新的查询计划如下所示:

使用更新级联更新查询计划

该计划有两个Clustered Index Update步骤,一个用于T1,一个用于T2.

更新1:

当多个主键值更新时,SQL Server如何跟踪要更新的行?

update T1
set T1.T1ID = T1.T1ID + 100
Run Code Online (Sandbox Code Playgroud)

查询计划更新与更新级联多个行

顶部分支(更新)中的Eager SpoolT1将旧T1ID计算和新计算保存T1ID (Expr1013)到下部分支(更新T2)使用的临时表中.在下面的分支哈希匹配与加盟表假脱机T2的老T1ID.从哈希匹配到的更新输出T2T2ID从的聚集索引扫描T2和新的计算T1ID (Expr1013)从表假脱机.

更新2:

如果你需要替换cascade updatea,instead of trigger你需要有一种方法来加入触发器中的inserteddeleted表.这可以通过代理键来完成T1.

表:

create table T1
(
  T1ID int primary key,
  ID int identity unique
);

create table T2
(
  T2ID int primary key, 
  T1ID int references T1(T1ID)
);
Run Code Online (Sandbox Code Playgroud)

触发器可能看起来像这样.

create trigger tr_T1 on T1 instead of update as

insert into T1(T1ID)
select T1ID
from inserted;

update T2
set T1ID = I.T1ID
from inserted as I
  inner join deleted as D
    on I.ID = D.ID
where D.T1ID = T2.T1ID;

delete from T1
where T1ID in (
              select T1ID
              from deleted
              );
Run Code Online (Sandbox Code Playgroud)

SQL小提琴

  • @ManishRawat是的,SQL计划正在告诉你SQL Server内部如何做到这一点,我认为这就是这个问题的意义所在.如果不修改表,就无法在触发器中执行此操作.你有三种方法来解决你的情况.**1**删除"T2"中没有有效FK到"T1"的所有行.**2**将所有必要的行添加到`T1`,以便`T2`中的所有行都有一个有效的FK.**3**在"T2"中允许FK中的空值,并且对于没有有效FK到"T1"的所有行,将"T2"中的FK更新为null. (3认同)
  • @ManishRawat不,没有.我不认为在触发器中有任何方法可以执行此操作,除非您可以在`T1`中添加某种代理键,您可以将其用作`inserted`和`deleted`之间的连接.它可以是具有唯一约束的`identity`列.标识列不必是主键.`create table T1(T1ID int主键,ID int identity unique);` (2认同)