我正在刷新我的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)为空时将其设置为零
我正在努力弄清楚如何构建条件,有人可以帮忙吗?
答案 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;