SQL Server:递归触发器

时间:2017-01-28 11:36:39

标签: sql-server sql-server-2008 triggers sql-server-2008-r2 rollback

我有一个表格,我在“ENABLED”列上创建了一个触发器,见下文:

CREATE TRIGGER [dbo].[TG_TESTS] 
ON [dbo].[TESTS] 
FOR UPDATE 
AS
    IF UPDATE([ENABLED]) 
      BEGIN 
         (...) 
      END

此触发器根据具体情况接收1行或多行。所有这些行总是有依赖关系,我的意思是,他们有孩子,例如:

表测试:

TEST_ID | PARENT_TEST_ID | ENABLED
  1            NULL          0
  3            NULL          0
  4            NULL          0
  5             1            0
  6             1            0
  7             4            0
  8             3            0

树木:

     1          3      4
    / \         |      |
   /   \        |      |
  5     6       8      7
  • 测试1取决于测试5和6
  • 测试3取决于测试8
  • 测试4取决于测试7

对于收到的每一行,都会按以下方式对ENABLED列进行更新:

  • 从顶部(父级)到底部(子级):如果我们收到更新为ENABLED = 1的测试父级,则尽可能将其所有子级和后代设置为ENABLED = 1。如果测试不能设置为ENABLED = 1,它将保持其旧值,前一个触发器被触发。

  • 从下到上:如果测试的所有子项都为ENABLED = 1或者可以切换到ENABLED = 1,那么test(parent)设置为ENABLED = 1,否则,如果有的话测试的子项不能切换到ENABLED = 1,然后测试父项将其值保持为ENABLED = 0(旧值)。

例如:

考虑到上面的树木:

  • 如果测试5是ENABLED = 1且测试6是ENABLED = 0并且我们收到了 将测试1上的更新设置为ENABLED = 1,然后将尝试将测试5和6设置为ENABLED = 1,如果不可能将测试1设置为其旧值ENABLED = 0.
  • 如果测试5和6都可以切换到ENABLED = 1并且我们收到了 将测试1上的更新设置为ENABLED = 1,然后将测试1设置为ENABLED = 1.

因此,当我们收到要更新的行时,要设置为ENABLED = 1,我们需要检查他们的子项并在可能的情况下更新它们,然后根据它们更新父项。

这是一个示例,但是可以存在许多依赖项,因此需要递归并且将存在,因为将需要在触发触发器的同一个表上进行更新。

所以我想到了两个选择:

  • 使用递归CTE
  • 使触发器递归

两种情况都需要更新触发触发器的同一个表,所以就我所知,不可能避免递归。

让我担心的是:

  • 数据库性能。我不知道是否同样发射递归 table是一个很好的做法,或者有其他方法可以做到这一点,并避免在这种情况下递归。
  • 在触发器中可以同时接收多个行的事实,它不允许使用命令回滚,因为我需要更新可能的测试。如果某些测试无法更新,我不能仅对它们使用rollback命令,回滚将应用于收到的所有行集,因此如果完成回滚,它将撤消所有,甚至是已正确更新的测试。

在这种情况下,这是最好的方法吗?

0 个答案:

没有答案