我一直在SQL Server中构建一些触发器。每个触发器的目的是更新相关记录上的一些数据(因为它们都是)。以下是其中一个触发器的示例:
CREATE TRIGGER dbo.bssProjects_Update
ON dbo.Projects
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- workflow to reset the pipelinestatus if the totalCharge changes. remember that there can be many changes at once
UPDATE
Proj
SET
Proj.[PipelineStage] = 11
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Projects Proj on Proj.ID = INS.ID
WHERE
(INS.[PipelineStage] > 11 and INS.[TotalCharge] != DEL.[TotalCharge])
-- workflow to reset the pipelinestatus if the totalCharge changes. remember that there can be many changes at once
UPDATE
Proj
SET
Proj.[PipelineStage] = 13
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN InvoiceLines Invce on Invce.bssToProjectID = INS.ID
INNER JOIN Projects Proj on Invce.bssToProjectID = Proj.ID
WHERE
(INS.[PipelineStage] > 11 and INS.[TotalCharge] != DEL.[TotalCharge])
-- workflow to reset the pipelinestatus if the totalCharge changes. remember that there can be many changes at once
UPDATE
Invce_2
SET
Invce_2.[InvoiceStatus] = 30
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN InvoiceLines Invce on Invce.bssToProjectID = INS.ID
INNER JOIN Invoices Invce_2 on Invce.bssToInvoiceID = Invce_2.ID
WHERE
(INS.[PipelineStage] > 11 and INS.[TotalCharge] != DEL.[TotalCharge])
-- workflow to reset the contributor status if the invoicable value changes.
UPDATE
Contrib
SET
Contrib.[Status] = 40
FROM
Inserted INS -- Project record
INNER JOIN Contributors Contrib on Contrib.bssToProjectID = INS.ID
WHERE
(Contrib.[Status] > 40)
and (INS.[TranslationCost] != INS.[T1NetInvoiced])
-- on total or cost allocation changes, recalc translator payment.
UPDATE
Contrib
SET
Contrib.[Payment] = (INS.[NetCharge] - INS.[DiscountCharge]) * CostAlloc.[TShare],
Contrib.[ManualPayment] = 0
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Contributors Contrib on Contrib.bssToProjectID = INS.ID
INNER JOIN luCostAllocations CostAlloc on INS.CostAllocation = CostAlloc.ID
WHERE
(Contrib.[ContributorRole] = 2)
and ((INS.[NetCharge] - INS.[DiscountCharge]) != (DEL.[NetCharge] - DEL.[DiscountCharge]) or INS.[CostAllocation] != DEL.[CostAllocation])
-- on total or cost allocation changes, recalc editor payment.
UPDATE
Contrib
SET
Contrib.[Payment] = (INS.[NetCharge] - INS.[DiscountCharge]) * CostAlloc.[EditorShare],
Contrib.[ManualPayment] = 0
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Contributors Contrib on Contrib.bssToProjectID = INS.ID
INNER JOIN luCostAllocations CostAlloc on INS.CostAllocation = CostAlloc.ID
WHERE
(Contrib.[ContributorRole] = 3)
and ((INS.[NetCharge] - INS.[DiscountCharge]) != (DEL.[NetCharge] - DEL.[DiscountCharge]) or INS.[CostAllocation] != DEL.[CostAllocation])
-- on total or cost allocation changes, recalc proofreader payment.
UPDATE
Contrib
SET
Contrib.[Payment] = (INS.[NetCharge] - INS.[DiscountCharge]) * CostAlloc.[ProofReaderShare],
Contrib.[ManualPayment] = 0
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Contributors Contrib on Contrib.bssToProjectID = INS.ID
INNER JOIN luCostAllocations CostAlloc on INS.CostAllocation = CostAlloc.ID
WHERE
(Contrib.[ContributorRole] = 4)
and ((INS.[NetCharge] - INS.[DiscountCharge]) != (DEL.[NetCharge] - DEL.[DiscountCharge]) or INS.[CostAllocation] != DEL.[CostAllocation])
-- on total or cost allocation changes, recalc devexec payment.
UPDATE
Contrib
SET
Contrib.[Payment] = (INS.[NetCharge] - INS.[DiscountCharge]) * CostAlloc.[PMShare],
Contrib.[ManualPayment] = 0
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Contributors Contrib on Contrib.bssToProjectID = INS.ID
INNER JOIN luCostAllocations CostAlloc on INS.CostAllocation = CostAlloc.ID
WHERE
(Contrib.[ContributorRole] = 5)
and ((INS.[NetCharge] - INS.[DiscountCharge]) != (DEL.[NetCharge] - DEL.[DiscountCharge]) or INS.[CostAllocation] != DEL.[CostAllocation])
-- on total or cost allocation changes, recalc devexec payment.
UPDATE
Contrib
SET
Contrib.[Payment] = (INS.[NetCharge] - INS.[DiscountCharge]) * CostAlloc.[DevExecShare],
Contrib.[ManualPayment] = 0
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Contributors Contrib on Contrib.bssToProjectID = INS.ID
INNER JOIN luCostAllocations CostAlloc on INS.CostAllocation = CostAlloc.ID
WHERE
(Contrib.[ContributorRole] = 6)
and ((INS.[NetCharge] - INS.[DiscountCharge]) != (DEL.[NetCharge] - DEL.[DiscountCharge]) or INS.[CostAllocation] != DEL.[CostAllocation])
-- clean up any temp tables created in creation process
END
很抱歉有这么多,但我想说明有很多事情要发生。然后我对项目记录做了一个简单的更改 - 一个不影响触发器中使用的任何值的一个,我得到一个错误:
超出最大存储过程,函数,触发器或视图嵌套级别(限制32)。
关于这一点,这意味着发生了太多的递归动作。每次更新都会导致调用另一个触发器 - 即使没有任何更改。实际上,我更改了触发器并用选择替换了所有更新并通过它进行了调试,发现没有正在进行的实际更新。这只是通过触发器来观察和看到。
问题在于我希望触发器按照请求运行,所以我在执行之前首先尝试了测试表达式的策略 - 只有在有某些事情要做时才调用更新。像这样:
declare @rows as int = 0;
select @rows = count(*)
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Projects THIS on THIS.ID = INS.ID
WHERE
(INS.[PipelineStage] > 11 and INS.[TotalCharge] != DEL.[TotalCharge])
if (@rows > 0)
BEGIN
UPDATE
THIS
SET
THIS.[PipelineStage] = 11
FROM
Inserted INS -- Project record
INNER JOIN Deleted DEL ON INS.ID = DEL.ID
INNER JOIN Projects THIS on THIS.ID = INS.ID
WHERE
(INS.[PipelineStage] > 11 and INS.[TotalCharge] != DEL.[TotalCharge])
END
它肯定会阻止递归。问题是,这是一个真正的NONO吗?我知道它会慢一些,但我认为它只会稍微慢一些,即使有事情要做,因为查询已经存在于实际查询中。
欢迎您的建议 克雷格
答案 0 :(得分:0)
在触发开始时,检查@@ROWCOUNT
是否为零,是否执行RETURN
退出触发器。您应该在第一个语句中执行检查(甚至在SET NOCOUNT ON
之前),因为任何语句可能会重置@@ROWCOUNT
,您可能会得到不同的结果。