【发布时间】:2018-04-20 08:37:52
【问题描述】:
(注意:我的问题非常详细且针对我们的系统,因此在我提前回答实际问题之前,我会为解释的长度道歉。)
我们有许多表需要将其中包含的部分数据汇总到另一个表中。
我已尽我所能确保触发器可以处理多行而不仅仅是单行事务:
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
而且它似乎可以工作,直到我们建立一个系统来“合并”账户,旧账户中的所有记录都将其 accountid 更改为主账户。
我试图完成的行为是更新聚合表中的任何现有记录,并为主帐户不存在的任何内容插入新记录。
所以我的问题是:If exists/elseif exists 子句的存在是否真的使这个触发器(以及以此触发器为模型的其余触发器)实际上不能处理多行?如果是这样,我认为我的问题不会通过为每个表编写 2 或 3 个单独的触发器来解决,因为我仍然必须每次都检查现有记录(即更新/删除触发器和单独的插入触发器)?我是否应该将所有这些移动到一个存储过程并传递一个表变量,例如,一个包含插入/删除表中所有记录的表变量(我想在论坛周围巡游)?
SQL 不是我的强项,更不用说触发。非常感谢有经验的人提供任何帮助。
【问题讨论】:
-
您是否考虑过使用索引视图来执行此聚合的可能性?如果您可以使用它们,我建议您这样做 - 在幕后,它们使用非常类似于触发器的东西,但该代码已被使用和测试比您希望的要多得多。跨度>
-
我相信没有人想到过一个观点。我会把这个想法告诉我的主管讨论。谢谢!
-
是的,存储可以计算的数据通常是不受欢迎的(因为你介绍机会计算数据与基础数据不一致)。如果你必须这样做,最好使用内置机制而不是自己编写(因为它们不太可能出现不一致或错过边缘情况)
-
我应该在此处发布更多信息以便清楚起见还是创建一个新问题来详细说明这种情况?
标签: sql-server triggers sql-server-2008-r2