SQL Server 删除触发器以更新同一表中的多个列

Posted

技术标签:

【中文标题】SQL Server 删除触发器以更新同一表中的多个列【英文标题】:SQL Server Delete Trigger To Update Multiple Columns in Same Table 【发布时间】:2010-06-23 15:52:22 【问题描述】:

我有以下触发器:

CREATE TRIGGER Users_Delete
   ON  Users 
   AFTER DELETE
AS 
BEGIN

    SET NOCOUNT ON;

    -- Patients
    UPDATE Patients SET ModifiedByID=NULL WHERE ModifiedByID=ID;
    UPDATE Patients SET CreatedByID=NULL WHERE CreatedByID=ID;
    UPDATE Patients SET DeletedByID=NULL WHERE DeletedByID=ID;

END

我想知道是否有办法将这三个 UPDATE 语句“组合”成如下所示的内容:

UPDATE Patients SET 
(ModifiedByID=NULL WHERE ModifiedByID=ID) OR 
(CreatedByID=NULL WHERE CreatedByID=ID) OR 
(DeletedByID=NULL WHERE DeletedByID=ID);

我真的很想只用一个语句来提高性能。

我之所以在ON DELETE 上为FOREIGN KEY 使用触发器,是因为我收到一个错误,即拥有多个ON DELETE 会导致以下错误:

在表“Patients”上引入 FOREIGN KEY 约束“FK_Patients_Users_Deleted”可能 导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

编辑:在所有 ModifiedByID、CreatedByID、DeletedByID 列上都有索引会更好吗?删除用户当然很少见,那么是否值得为 3 列添加索引?

【问题讨论】:

令我困扰的是,您完全改变了这些数据。停用用户比删除具有关联的子记录的用户要好。现在您将无法分辨谁创建了该记录,这可能具有一定的重要性,尤其是当用户因性能原因被解雇时。 这实际上是一个非常有效的观点。我会考虑到这一点。 【参考方案1】:

关于你原来的问题。

不是真的。我想不出比这更好的了

UPDATE Patients 
SET ModifiedByID= CASE WHEN ModifiedByID=ID THEN NULL ELSE ModifiedByID END,
CreatedByID= CASE WHEN CreatedByID=ID THEN NULL ELSE CreatedByID END,
DeletedByID= CASE WHEN DeletedByID=ID THEN NULL ELSE DeletedByID END
WHERE
ModifiedByID  IN (SELECT ID FROM DELETED)
OR 
CreatedByID  IN (SELECT ID FROM DELETED)
OR
DeletedByID  IN (SELECT ID FROM DELETED)

请注意,这可以正确处理多行删除。从您发布的内容中不清楚您当前的触发器是否有效。

【讨论】:

重要的一点,许多人针对单个记录编写代码并由于多行操作而失败。【参考方案2】:

这样的?

UPDATE Patients SET 
ModifiedByID = CASE WHEN ModifiedByID=ID THEN Null ELSE ModifiedById END,
CreatedByID = CASE WHEN CreatedByID=ID THEN Null ELSE CreatedById END,
DeletedByID = CASE WHEN DeletedByID=ID THEN Null ELSE DeletedById END
WHERE (ModifiedByID = ID OR CreatedByID = ID OR DeletedByID = ID)

【讨论】:

我猜您会看到性能提升的唯一情况是,Patients 表非常大并且您在 ModifiedByID、CreatedByID 或 DeletedByID 上没有适当的索引。在这种情况下,解决方案是添加索引 那么您认为最好将这 3 个语句与 ModifiedByID/CreatedByID/DeletedByID 上的索引一起使用? 我强烈怀疑它几乎没有区别,所以我会选择更容易理解的那个(即三个语句) 好的,我会去的。您认为在 3 列上有索引很重要吗?更新索引不是很昂贵吗? 一般经验法则:在写入数据时进行打击,以便加快读取数据的速度。优化 SQL 很有趣,因为您可以将读取提高几个数量级。顺便说一句,我会注意到 HLGEM 关于你为什么要这样做的评论(当你可以进行软删除时),以及 Martin Smith 关于多次删除的观点,这很容易被忽视。【参考方案3】:

您可以在一个语句中做到这一点,但这并不一定会提高性能。

UPDATE
    Patients
SET
    ModifiedByID = CASE WHEN ModifiedID = ID THEN NULL ELSE ModifiedID,
    CreatedByID = CASE WHEN CreatedByID = ID THEN NULL ELSE CreatedByID,
    DeletedByID = CASE WHEN DeletedByID = ID THEN NULL ELSE DeletedByID

我真的怀疑这会表现得更好。

【讨论】:

以上是关于SQL Server 删除触发器以更新同一表中的多个列的主要内容,如果未能解决你的问题,请参考以下文章

插入后使用 SQL Server 触发器更新另一个表中的列

SQL Server2008 触发器中,根据一个表修改另外一个表

SQL Server:根据应用程序用户记录数据库更改

SQL Server 触发器切换插入、删除、更新

sqlserver创建一个新表,求助

MySql 触发器删除同一张表中的子记录