来自另一个表的带有循环的 SQL 触发器

Posted

技术标签:

【中文标题】来自另一个表的带有循环的 SQL 触发器【英文标题】:SQL Trigger with loop from another table 【发布时间】:2021-08-29 08:13:50 【问题描述】:

我有 2 张桌子:

表 A

create table A
(id int identity(1,1)
,KeyWord1 nvarchar(50)
,KeyWord2 nvarchar(50)
,KeyWord3 nvarchar(50)
)

表 B

Create table B
(id int identity(1,1)
,Address nvarchar(150)
,Chk int
)

表 A 包含以下值:

insert into A
values
(166, 'elyse', 'vry')
,(243, 'virginia', 'beach')
,(134, 'aris', 'adium')

表 B 包含以下值:

insert into B
values
('35 stadium street, 134 Paris', null)
,('243, Stadiumù road from Paris', null)

当在表 B 上创建新行时,我的目标是使用表 A 中的出现次数设置列 B.chk。

例如:

insert into B
values
('166, road to Champs elysee - 14215 Cdx Evry', null)

表 B 上的触发器应将 B.Chk 设置为 1,因为以下查询与表 A 匹配

select count(*) from inserted
where b.Address like '%166%'
and b.Address like '%elyse%'
and b.Address like '%vry%'

为此,我应该在表 B 上创建一个触发器,但不知道如何在另一个表上“循环”。 我应该使用 for、while 还是 cursor?

【问题讨论】:

循环是什么意思,你打算循环什么? SQL 是声明性语言,它接受带有where 条件的select 语句并返回没有循环的答案 样本数据,以及应该匹配和不匹配的示例将非常有帮助。 触发器几乎总是一个坏主意。您真的需要立即填充此字段吗?还是您只是想生成一份报告来确定这一点? 不需要循环,但如果你不需要在触发器中进行非sargable查找对其性能没有好处 列立即更新,您应该定期安排此过程。 tag您的特定数据库平台。 是的,我需要一个触发器,因为该列的值将从另一个应用程序启动工作流。 【参考方案1】:

您的触发器需要被构造为将inserted 虚拟表视为一个集合,就像在任何其他 SQL 语句中一样。

您不需要也不应该使用局部变量来保存触发器中的值,因为触发器对受影响的行集进行操作。

请尝试以下方法:

create or alter trigger TR_Update_B
on dbo.B
after insert
as
set nocount on;

with t as (
    select i.id, Count(*) qty
    from inserted i 
    join a on
            i.Address like '%' + a.KeyWord1 + '%' 
        and i.Address like '%' + a.KeyWord2 + '%' 
        and i.Address like '%' + a.KeyWord3 + '%' 
    group by i.id
)
update b set
b.chk=t.qty
from t
join b on b.id=t.id;

【讨论】:

【参考方案2】:

你说得对,我不需要循环,但插入后需要立即设置 chk 列。

这是我的触发器:

 Create trigger TR_Update_B
 ON dbo.B
 AFTER insert
 AS
 BEGIN

 SET NOCOUNT ON;

 DECLARE @docNo int
 DECLARE @Result int

 SELECT @DocNo=id FROM inserted;

 SET @Result= (select count(*) from b
 join a
 on b.Address like '%'+a.KeyWord1+'%' 
 and b.Address like '%'+a.KeyWord2+'%' 
 and b.Address like '%'+a.KeyWord3+'%' 
 where b.id=@DocNo)

 Update b set Chk = @Result where id=@DocNo

 END

【讨论】:

从这里我可以看到你想要做什么。不幸的是,您创建了一个具有经典且常见缺陷的触发器,因为您的触发器假定不会插入超过一行。如果插入 2 行,@docNo 的值是多少?触发器每条语句触发 一次,因此如果您插入 10 行,它将运行一次,@docNo 将是一个(随机)Id

以上是关于来自另一个表的带有循环的 SQL 触发器的主要内容,如果未能解决你的问题,请参考以下文章

SQL语句循环一张表的一个字段ID,根据这个字段的内容去修改另一张表,

使用来自两个表的变量的 SQL 触发器

SQL触发器循环插入到另一个表

sql 中如何设置触发器使修改一个表中列的值时,同时修改另一个表的值

SQL Server在复制时触发

关于使用sql server 2008触发器完成修改一张表里一个字段同时修改另一张表的另一字段