(注意:我的问题详细而且具体到我们的系统,所以在我事先得到实际问题之前,我会为解释的长度道歉。)
我们有许多表需要将其中包含的部分数据汇总到另一个表中。
我尽力确保触发器可以处理多行而不仅仅是单行事务:
TRIGGER [dbo].[TR_SavedFiles_PlanLibraryMetrics] on [dbo].[SavedFiles]
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON
BEGIN
IF EXISTS (
SELECT m.AccountID, m.PlanLibCode
FROM PlanLibraryMetrics AS m
JOIN PlanLibraryItems AS it
ON m.PlanLibCode = it.PlanLibCode
JOIN inserted AS i
ON m.AccountID = i.AccountID
AND (it.ItemTypeID = i.CISFileID AND it.ItemType = 'FILE')
JOIN Accounts AS a ON i.AccountID = a.AccountID
WHERE a.Status = 0
)
BEGIN
UPDATE PlanLibraryMetrics
SET MetricValue = x.newValue
FROM (SELECT COUNT(s.AccountID) AS newValue, it.PlanLibCode, i.AccountID
FROM SavedFiles AS s
JOIN PlanLibraryItems AS it
ON (s.CISFileID = it.ItemTypeID AND it.ItemType = 'FILE')
JOIN inserted AS i
ON s.AccountID = i.AccountID
AND s.CISFileID = i.CISFileID
Group By PlanLibCode, i.AccountID) AS x
JOIN PlanLibraryMetrics AS m
ON x.PlanLibCode = m.PlanLibCode
AND x.AccountID = m.AccountID
END
ELSE IF EXISTS (
SELECT m.AccountID, m.PlanLibCode
FROM PlanLibraryMetrics AS m
JOIN PlanLibraryItems AS it
ON m.PlanLibCode = it.PlanLibCode
JOIN deleted AS d
ON m.AccountID = d.AccountID
AND (it.ItemTypeID = d.CISFileID AND it.ItemType = 'FILE')
JOIN Accounts AS a ON d.AccountID = a.AccountID
WHERE a.Status = 0
)
BEGIN
UPDATE PlanLibraryMetrics
SET MetricValue = x.newValue
FROM (SELECT COUNT(s.AccountID) AS newValue,it.PlanLibCode, d.AccountID
FROM SavedFiles AS s
RIGHT OUTER JOIN deleted AS d
ON s.AccountID = d.AccountID
AND s.CISFileID = d.CISFileID
JOIN PlanLibraryItems AS it
ON (d.CISFileID = it.ItemTypeID AND it.ItemType = 'FILE')
Group By PlanLibCode, d.AccountID) AS x
JOIN PlanLibraryMetrics AS m
ON x.PlanLibCode = m.PlanLibCode
AND x.AccountID = m.AccountID
END
ELSE IF NOT EXISTS (
SELECT m.AccountID, m.PlanLibCode
FROM PlanLibraryMetrics AS m
JOIN PlanLibraryItems AS it ON m.PlanLibCode = it.PlanLibCode
JOIN inserted AS i
ON m.AccountID = i.AccountID
AND (it.ItemTypeID = i.CISFileID AND it.ItemType = 'FILE')
JOIN Accounts AS a ON i.AccountID = a.AccountID
WHERE a.Status = 0
)
BEGIN
INSERT INTO PlanLibraryMetrics
SELECT i.AccountID, it.PlanLibCode, COUNT(s.AccountID)
FROM SavedFiles AS s
JOIN PlanLibraryItems AS it
ON (s.CISFileID = it.ItemTypeID AND it.ItemType = 'FILE')
JOIN inserted AS i
ON s.AccountID = i.AccountID
AND s.CISFileID = i.CISFileID
Group By PlanLibCode, i.AccountID
END
END
它似乎有效,直到我们到达一个系统,我们已经到位“合并”帐户,从旧帐户的所有记录都将其帐户更改为主帐户。
我想要完成的行为是更新聚合表中的任何现有记录,并为主帐户尚不存在的任何内容插入新记录。
所以我的问题:If exists / elseif exists子句的存在是否实际上使得这个触发器(以及在此模型上建模的其余触发器)实际上并不处理多行?如果是这样,我认为我的问题不会通过为每个表写入2或3个单独的触发器来解决,因为我仍然必须每次检查现有记录(即更新/删除触发器和单独的插入触发器)?我应该将所有这些移动到存储过程并传入,例如,一个表变量,其中包含插入/删除表中的所有记录(我想在论坛中巡航)?
SQL不是我的强项并且触发更少。任何经验丰富的人都会非常感激。
答案 0 :(得分:2)
简短回答 - 不。使用"如果存在"不会阻止正确处理多行语句。
但是说实话。如果您在使用tsql和触发器时遇到困难,那么您应该为每个操作编写单独的触发器 UNTIL 您对自己的方法和逻辑有信心。
您的逻辑似乎过于复杂,但没有人知道您的架构以及您的表的使用方式。它似乎至少有一个错误。在插入部分中,基于a.Status = 0检查是否存在。相关的插入语句中不包含相同的逻辑。这已经传播到另外两组逻辑。
例如,假设在SavedFiles中插入了5行。 1匹配PlanLibraryMetrics中的一行,其他人不同意。你的代码做了什么?执行后,PlanLibraryMetrics中只会更新一行 - 您已跳过聚合/插入其他4行所需的逻辑。你的删除逻辑似乎对正确的连接非常怀疑;在不知道各种表的实际和逻辑键的情况下,很难理解。
并且就此而言 - 现在是开始评论您的代码以帮助其他人(包括您自己以后)了解代码应该做什么以及可能为什么的好时机。是的 - 请考虑Damien的建议。索引与否的视图可能(可能是)更好的方法 - 当然也是更安全,更容易维护的方法。