SQL - 在更新触发器中删除更新的行

Posted

技术标签:

【中文标题】SQL - 在更新触发器中删除更新的行【英文标题】:SQL - Delete updated row in update trigger 【发布时间】:2012-04-02 14:11:06 【问题描述】:

我的更新触发器有问题

ALTER TRIGGER tr_MyTable
ON  MyTable
AFTER UPDATE
AS 

BEGIN TRAN
SET NOCOUNT ON;

      If Update(column)
      Begin
           DELETE FROM MyTable WHERE <condition>
      End


      SET NOCOUNT OFF
COMMIT TRAN
GO

我正在尝试删除当前已在 MyTable 中更新的行(来自 MayTable)。但是当我运行触发器时,该行没有被删除。是否无法删除当前已在更新触发器中更新的行? (删除和更新在同一张表上)

谢谢!

编辑:

ALTER TRIGGER tr_MyTable
ON  MyTable
AFTER UPDATE
AS 

BEGIN TRAN
SET NOCOUNT ON;

      SELECT @ID = ID
      FROM   inserted

      If Update(column)
      Begin
           DELETE FROM MyTable WHERE ID = @ID
      End


      SET NOCOUNT OFF
COMMIT TRAN
GO

编辑 2:

ALTER PROCEDURE sp_Update
(
@ID INTEGER,)
AS

SET NOCOUNT ON
Begin Tran

            Update MyTable SET Column = Data where ID = @ID

      Commit Tran
SET NOCOUNT OFF
GO

此更新程序正在运行,并且该列已更新。触发器也被触发,并且执行删除(打印语句)之前的行,但不执行删除语句。 但是当我直接在表中更新列时,不形成触发器触发的程序并且删除语句正常工作。我不使用回滚。

【问题讨论】:

你在 SQl 服务器中犯了最严重的触发器错误,即假设只有一条记录将被插入或删除表。如果您执行批量插入,这将不起作用。此代码完全错误,必须更改。 另外,你不应该用 sp_ 开始存储过程,因为这是系统过程使用的。此外,您不应该在没有 try-catch 块的情况下编写事务,以便可以回滚。 【参考方案1】:

你是怎么删除的?

您应该从您的 INSERTED 和 DELETED 表中读取您的值,例如:

DELETE FROM MyTable WHERE id in (select ID from INSERTED)

【讨论】:

【参考方案2】:

也许您想在 INSTEAD OF 触发器中执行此操作。如果有人尝试更新该列,您可以删除该行,否则您重新执行更新。这里唯一的挑战是您必须在触发器中重新编码更新语句。 (此外,您实际上并不需要在触发器内添加额外的 BEGIN TRAN/COMMIT TRAN。)

CREATE TRIGGER dbo.tr2_myTable
ON dbo.MyTable
INSTEAD OF UPDATE
AS
BEGIN
  SET NOCOUNT ON;

  -- update the rows where the column hasn't changed
  UPDATE s
    SET col1 = i.col1, col2 = i.col2, ...
    FROM dbo.MyTable AS s
    INNER JOIN inserted AS i
    ON s.key = i.key
    INNER JOIN deleted AS d
    ON i.key = d.key
    AND i.column_that_should_not_change = d.column_that_should_not_change;

  -- delete the rows where the column HAS changed
  -- (note that this requirement sounds odd to me)
  DELETE s
    FROM dbo.MyTable AS s
    INNER JOIN inserted AS i
    ON s.key = i.key
    INNER JOIN deleted AS d
    ON i.key = d.key
    AND i.column_that_should_not_change <> d.column_that_should_not_change;
END
GO

请注意,与您的 IF UPDATE() 逻辑不同,此触发器实际上将处理多行(例如,该列已更改的部分,而未更改的部分)。另请注意,即使有人说UPDATE foo SET x = x;IF UPDATE(x) 也会为真。

这假设您有一个键列,并且 column_that_should_not_change 不可为空。如果此列允许 NULL,则逻辑会变得更复杂。

【讨论】:

【参考方案3】:

有可能。

如果您愿意,您可以在触发器中添加DELETE FROM MyTable,这应该可以。您是否进行了测试以确认触发器正在执行并且您的代码到达DELETE FROM MyTable WHERE &lt;condition&gt; 行?

【讨论】:

是的,触发器正在执行,并且在执行 行的 MyTable 中删除之前的行,因此也应该执行删除行。我从 Diego 提到的插入表中选择了我的 那么我认为它必须是 总是错误的。为什么不向我们展示完整的 DELETE 行代码? “如果更新(列)”在做什么?您是否 100% 确定 ID 是唯一的? ...就我所见,它应该可以工作。我在我的机器上创建了一个类似的场景,并且更新的行被成功删除。 这可能是我的问题...我的情况是我从存储的过程中更新了 MyTable 中的列,当我这样做时触发器触发,并在触发器中执行删除。但是问题是我从存储的prosedyre进行更新并且在提交整个操作之前触发触发器(在提交带有更新语句的prosedure之前)? 存储过程就像一个大事务,触发器是一个嵌套事务。它也应该从存储过程中工作。除了......存储过程中有任何“回滚”指令吗?你能展示你的完整代码,包括完整的过程和完整的触发器吗?

以上是关于SQL - 在更新触发器中删除更新的行的主要内容,如果未能解决你的问题,请参考以下文章

更新/插入/删除表中的行后触发的触发器有问题

(SQL/PLSQL) 在触发期间显示更新的行

更新后触发并更新到 SQL Server 中的行

PL/pgSQL:删除(更新)与记录匹配的行

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

PL/SQL ORACLE:删除时触发更新