用于将总计合并到父表的SQL触发器(带有已取消的列)

时间:2014-07-22 05:50:07

标签: sql sql-server triggers

我有这个触发器将列值合并到其父表。在这种情况下,InvoiceTotal被添加/减去帐户的InvoiceTotal

WITH Deltas as (
    SELECT AccountID, Sum(InvoiceTotal) as InvoiceTotal From inserted Group By AccountID
    UNION ALL
    SELECT AccountID, Sum(InvoiceTotal * -1) as InvoiceTotal From deleted Group By AccountID
),
Merged as
    (Select AccountID, Sum(InvoiceTotal) InvoiceTotal From Deltas Group by AccountID)
Update Account set InvoiceTotal = Account.InvoiceTotal + Merged.InvoiceTotal From Merged Where Account.AccountID = Merged.AccountID;

现在我在发票表中有一个名为IsCancelled的新列。如何修改上面的触发器来处理?如果取消发票,则帐户总数应减少,如果IsCancelled设置为0,则应增加。

是否可以在一个SQL语句中执行上述任务?

由于

4 个答案:

答案 0 :(得分:1)

WITH Deltas as (
    SELECT AccountID, CASE WHEN IsCancelled=0 THEN Sum(InvoiceTotal) ELSE Sum(InvoiceTotal*-1) END as InvoiceTotal From inserted Group By AccountID
    UNION ALL
    SELECT AccountID, CASE WHEN IsCancelled=0 THEN Sum(InvoiceTotal*-1) ELSE Sum(InvoiceTotal) END  as InvoiceTotal From deleted Group By AccountID
),
Merged as
    (Select AccountID, Sum(InvoiceTotal) InvoiceTotal From Deltas Group by AccountID)
Update Account set InvoiceTotal = Account.InvoiceTotal + Merged.InvoiceTotal From Merged Where Account.AccountID = Merged.AccountID;

条件可能会对此有所帮助。

更新已删除的部分。

答案 1 :(得分:0)

我认为使用Indexed视图而不是触发器以获得发票的总价更好。我建议你有以下索引视图:

CREATE VIEW vw_InvoiceTotal With SCHEMABINDING 
AS 
    SELECT AccountId, 
             SUM (CASE WHEN IsCancelled=0 THEN InvoiceTotal ELSE -InvoiceTotal END) as InvoiceTotal,
             Count_Big(*) AS c
    FROM Deltas 
    GROUP By AccountId
End


CREATE UNIQUE CLUSTERED INDEX PK_InvoiceTotal ON dbo.vw_InvoiceTotal (AccountId)

通过这种方式,SQL Server可以通过表上的内部触发器自动同步索引视图。并且您可以将此视图用于以上性能。

SELECT * FROM vw_InvoiceTotal WITH(NOEXPAND)

如果你需要在你的mastertable中有InvoiceTotal列,我建议你有以上索引视图并在Deltas表上有以下触发器:

Create Trigger tr_sync_deltas on dbo.deltas
AFTER INSERT, UPDATE, DELETE
AS Begin
    Update MasterTable
    Set InvoiceTotal = ISNULL(i.InvoiceTotal,0)
    From (
       Select AccountId From Inserted
       Union
       Select AccountId From deleted
       )z
    Left Join dbo.vw_InvoiceTotal i on i.AccountId = z.AccountId
    Where MasterTable.AccountId = z.AccountId
End

答案 2 :(得分:0)

是的,我相信通过使用带有WHEN MATCHED / NOT MATCHED结构的MERGE可以在SQL Server上实现,您可以根据需要添加任意数量的AND条件。

具体请参阅Microsoft在MERGE上的参考,参见示例B. 使用MERGE在单个语句中对表执行UPDATE和DELETE操作

我没有在我的回复中粘贴它,因为我现在没时间重新考虑这个例子以符合您的情况,我会尝试。无论哪种方式,这应该可以满足您的需求。

答案 3 :(得分:0)

通过将IsCancelled标记添加到发票表中,您说当取消发票时,您希望从帐户余额中删除该发票总金额。另一种说法是,当IsCancelled = 1时,InvoiceTotal应被视为0,并相应地更新帐户余额。例如:如果旧发票总额为100,然后取消该发票,则应从帐户表中减去100(插入/新值0减去已删除/旧值为100)。在这种情况下,您可以按如下方式更新触发器查询。

WITH Deltas as (
    SELECT AccountID, Sum(case when IsCancelled = 0 then InvoiceTotal else 0 end) as InvoiceTotal From inserted Group By AccountID
    UNION ALL
    SELECT AccountID, Sum(case when IsCancelled = 0 then InvoiceTotal * -1 else 0 end) as InvoiceTotal From deleted Group By AccountID
),
Merged as
    (Select AccountID, Sum(InvoiceTotal) InvoiceTotal From Deltas Group by AccountID)
Update Account set InvoiceTotal = Account.InvoiceTotal + Merged.InvoiceTotal From Merged Where Account.AccountID = Merged.AccountID;

这是一个SQL小提琴,其中包含了这个实例。 http://sqlfiddle.com/#!6/e0246/16