Chinook数据库的SQL触发器:sum为null时的条件

时间:2015-04-09 20:17:55

标签: sql sql-server triggers conditional

我正在刷新我的SQL并使用Chinook数据库进行练习。

可在此处找到数据模型:https://chinookdatabase.codeplex.com/wikipage?title=Chinook_Schema&referringTitle=Documentation

目标是编写一个触发器,以便在插入或删除invoicelines时更新Invoice表中的Total。

CREATE TRIGGER UpdateTotal ON InvoiceLine
AFTER INSERT, DELETE
AS
    UPDATE Invoice
    SET Total = (
        SELECT sum(LineSum) AS InvoiceTotal
        FROM (
            SELECT InvoiceId, (UnitPrice * Quantity) AS LineSum 
            FROM InvoiceLine 
        ) AS WithLineSum
        GROUP BY InvoiceId
        HAVING WithLineSum.InvoiceId = Invoice.InvoiceId
    )

这在我插入和删除invoiceline记录时效果很好,除了我删除发票的最后一张发票时。当我这样做时,我得到错误:

无法将值NULL插入“Total”列,表'Chinook.dbo.Invoice';列不允许空值。 更新失败。

所以基本上我需要在sum(LineSum)为空时将其设置为零

我正在努力弄清楚如何构建条件,有人可以帮忙吗?

3 个答案:

答案 0 :(得分:0)

你应该将子查询包装在COALESCE中,基本上是

SET Total = COALESCE(...subquery..., 0)

答案 1 :(得分:0)

此触发器将更新每次记录更改时您不想要执行的每张发票。您需要查看插入和删除的伪表,以仅更新已更改的发票。

接下来,请考虑不使用相关子查询。您需要触发器代码尽可能快,并且使用连接的更新可能更快(当然测试)

最后,你可以在总和上使用coalesce,这样如果它为null,它会将sume更新为零。

答案 2 :(得分:0)

由于您每次更新每个发票而不是仅受操作影响的那些发票,因此您的方法效率低下。您需要利用触发器中的特殊Inserted and Deleted tables

CREATE TRIGGER UpdateTotal ON InvoiceLine
AFTER INSERT, DELETE
AS
    SET NOCOUNT ON;

    UPDATE Inv
    SET Total = Total + (i.UnitPrice * i.Quantity)
        FROM Inserted i
            INNER JOIN Invoice Inv
                ON i.InvoiceId = Inv.InvoiceId;

    UPDATE Inv
    SET Total = Total - (d.UnitPrice * d.Quantity)
        FROM Deleted d
            INNER JOIN Invoice Inv
                ON d.InvoiceId = Inv.InvoiceId;