Sql 无限触发循环…通过设计(!)。如何工作?
我知道我会因此被炒鱿鱼,但是 我有表ProductA、ProductB和ProductC,它们具有非常相似的模式,但每个表中有2或3列。每个表都有一个insert触发器,它为表产品a、B或C中的每个insert触发一个重复行,这是所有产品的合并。此外,A、B或C上的update触发器也会像delete触发器一样更新其在表产品中的等效行。所有这些都可以完美地工作,直到……比如说,我们更新了表A、表B和表C中的表产品列A 我希望在表产品上开发一个触发器,将表a、B和C中的a列中的更新传播到a列,但不调用表a、B和C上的更新触发器。所需的行为是更新在两个方向上都工作,而不会产生无休止的循环。(注意,表产品中只有2列需要复制回表A、B和C) 选项包括:Sql 无限触发循环…通过设计(!)。如何工作?,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我知道我会因此被炒鱿鱼,但是 我有表ProductA、ProductB和ProductC,它们具有非常相似的模式,但每个表中有2或3列。每个表都有一个insert触发器,它为表产品a、B或C中的每个insert触发一个重复行,这是所有产品的合并。此外,A、B或C上的update触发器也会像delete触发器一样更新其在表产品中的等效行。所有这些都可以完美地工作,直到……比如说,我们更新了表A、表B和表C中的表产品列A 我希望在表产品上开发一个触发器,将表a、B和C中的a列中的更新传播到a列,但不
ALTER TRIGGER [dbo].[tbl_locations_updateto_geo]
ON [dbo].[TBL_LOCATIONS]
for update
AS
BEGIN
--IF @@NESTLEVEL>1 RETURN
SET NOCOUNT ON;
update dbo.GRSM_Wetlands_Point
set
X_Coord = i.X_Coord,
Y_Coord = i.Y_Coord,
PlaceName = i.PlaceName,
FCSubtype = i.FCSubtype,
Landform = i.Landform,
from dbo.TBL_LOCATIONS
Join inserted i
on TBL_LOCATIONS.GIS_Location_ID = i.GIS_Location_ID
where TBL_LOCATIONS.FCSubtype = 'Polygon: Determination Made by GPS Survey'
or TBL_LOCATIONS.FCSubtype = 'Polygon: Determination Derived from NWI'
or TBL_LOCATIONS.FCSubtype = 'Polygon: Determination Made by Other Means'
or TBL_LOCATIONS.FCSubtype = 'Polygon: Legal Jurisdictional Determination';
end
GO
(更改tbl名称以与发布文本保持一致)有两种递归类型,直接递归和间接递归: 您可以使用RECURSIVE_TRIGGERS选项来停止直接递归,但您的案例是间接递归,因此您必须设置嵌套触发器选项。这将解决您的问题,但如果系统中的任何其他内容依赖于递归,那么它将不是一个好选项
USE DatabaseName
GO
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'nested triggers', 0
GO
RECONFIGURE
GO
编辑以响应更新的帖子:
我几乎不愿意给你这个解决方案,因为你最终会采用一个非常糟糕的设计并对其进行扩展…造成比现在更大的混乱,而不是花时间去理解正在发生的事情并修复它。你应该诚实地创建另一个表来保存两个t之间需要同步的值所以数据只在一个地方,然后通过一个键将这些表与那个地方关联起来
你需要一个标志来设置你在一个触发器中更新的内容,这样如果另一个触发器看到它是真的,它就可以中止它的操作。因为(据我所知)你只能有一个局部作用域变量,这意味着你需要一个表来存储这个标志值并从中查找它
您可以以不同的复杂程度实现此解决方案,但最简单的方法是让所有触发器在启动时将标志设置为true,在结束时将标志设置为false。在它们启动之前,它们检查标志,如果标志为true,则停止执行
这样做的问题是,可能会有另一个与触发器无关的更新同时发生,并且不会传播到下一个表中。如果您想采用此方法,那么我将让您自行决定如何解决该问题。假设您必须保留触发器,我可以想象一个涉及
rowversion
对于每个表,在每个表中存储其他表的更新。更新是否需要实时?如果不需要,那么一个简单的存储过程来同步这些表将是一个更简单的解决方案。您可以将其设置在时间表上。查看一下。另一种方法,使用与自己交谈,在接受的答案中进行了描述这就是我的问题。虽然我会说,如果系统中的其他任何东西都依赖于嵌套触发器,那么如果可能的话,它可能应该重新设计。一般来说,我会尽可能避免使用触发器。我偶尔会在非常非常简单的任务中使用它们;但当它们崩溃时,你甚至不知道它们在那里,它们会让你感到非常痛苦错误消息中没有任何内容提示您触发器导致了问题。好的,谢谢您的回答!我尝试了所有方法,解决了嵌套级别函数,但仍然无法使其工作。我编辑了原始帖子,以包含当前存在的触发器sytax。我编辑的答案的一个例外是如果GRSM\u\Poly是一个包含GRSM_湿地_POINT的观点。我怀疑这是否属实,但如果让我知道,我会再看一遍。Brandon Moore更新了我的帖子,你是对的,有点奇怪。我在复制和粘贴文本,并对文本进行了胖手指操作。
ALTER TRIGGER [dbo].[tbl_locations_updateto_geo]
ON [dbo].[TBL_LOCATIONS]
for update
AS
BEGIN
--IF @@NESTLEVEL>1 RETURN
SET NOCOUNT ON;
update dbo.GRSM_Wetlands_Point
set
X_Coord = i.X_Coord,
Y_Coord = i.Y_Coord,
PlaceName = i.PlaceName,
FCSubtype = i.FCSubtype,
Landform = i.Landform,
from dbo.TBL_LOCATIONS
Join inserted i
on TBL_LOCATIONS.GIS_Location_ID = i.GIS_Location_ID
where TBL_LOCATIONS.FCSubtype = 'Polygon: Determination Made by GPS Survey'
or TBL_LOCATIONS.FCSubtype = 'Polygon: Determination Derived from NWI'
or TBL_LOCATIONS.FCSubtype = 'Polygon: Determination Made by Other Means'
or TBL_LOCATIONS.FCSubtype = 'Polygon: Legal Jurisdictional Determination';
end
GO
USE DatabaseName
GO
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'nested triggers', 0
GO
RECONFIGURE
GO