2017-02-15 83 views
0

我有一個像這樣的「Order」表,其中包含有關訂單的信息。MS SQL使一個表的列取決於其他表值sum

Order ID | ... | Order Total

的順序,但是,由幾個項目,這裏還有一個 「項目訂單」 表:

Item Order ID | Order ID | Item ID

與 「項目」 表:

Item ID | Cost

因此,訂單< - >項目訂單具有一對多關係tionship和物品訂單< - >物品具有多對一的關係。

從邏輯上講,訂單合計應取決於其中每個項目訂單的成本,這會將項目的成本添加到合計中。

如何設置依存關係,以使訂單總計取決於與此訂單對應的所有項目訂單,並彙總所有需要的項目成本?我猜它也應該每次在訂單中添加新的項目訂單時更新。

+1

我建議不要*存儲*數據,你可以*計算*,除非和直到你可以證明一個實際的性能問題,只是在飛行中計算結果。只要你*存儲*冗餘數據,你打開自己的機會,它*錯*。 –

回答

0

您可以在Item OrderItem表上創建兩個觸發器。

觸發Item表:

CREATE TRIGGER T_Item_Recalc_Order_Total 
ON Item 
FOR DELETE, INSERT, UPDATE 
AS 
BEGIN 
SET NOCOUNT ON 

    UPDATE o 
     SET [Order Total] = c.[Cost] 
    FROM Order o 
     INNER JOIN 
     (
      SELECT i_o.[Order_ID] 
        ,SUM(Cost) AS Cost 
      FROM Item_Order i_o 
       INNER JOIN Item i 
        ON i.[Item ID] = i_o.[Item ID] 
      WHERE i_o.[Item ID] IN (
       -- Sum up cost for changed rows only 
       SELECT COALESCE(d.[Item ID], i.[Item ID]) AS [Item ID] 
       FROM deleted d 
        FULL OUTER JOIN inserted i 
         ON d.[Item ID] = i.[Item ID] 
       WHERE d.[Item ID] IS NULL OR i.[Item ID] IS NULL OR d.[Cost] <> i.[Cost] 
      ) 
      GROUP BY i_o.[Order_ID] 
     ) c 
      ON o.[Order_ID] = c.[Order_ID] 

END 

觸發Item Order表:

CREATE TRIGGER T_Item_Order_Recalc_Order_Total 
ON Item_Order 
FOR DELETE, INSERT, UPDATE 
AS 
BEGIN 
SET NOCOUNT ON 

    UPDATE o 
     SET [Order Total] = c.[Cost] 
    FROM Order o 
     INNER JOIN 
     (
      SELECT i_o.[Order_ID] 
        ,SUM(Cost) AS Cost 
      FROM Item_Order i_o 
       INNER JOIN Item i 
        ON i.[Item ID] = i_o.[Item ID] 
      WHERE i_o.[Order_ID] IN (
       -- Sum up cost for changed rows only 
       SELECT deleted.[Order_ID] 
       UNION 
       SELECT inserted.[Order_ID] 
      ) 
      GROUP BY i_o.[Order_ID] 
     ) c 
      ON o.[Order_ID] = c.[Order_ID] 

END 
+0

第一個觸發器已損壞。 「IF」假定「插入」和「刪除」包含零或一行。這是一個不安全的假設。 –

+0

@Damien_The_Unbeliever,謝謝。我將該邏輯移入了WHERE條款 – Serge

1

正如在評論中指出的,我通常不喜歡存儲冗餘,可能不正確的數據。但是,如果在運行中計算總計時存在性能問題,則下一個最佳選擇是讓系統爲您執行計算。如果您使用索引視圖,則這是一個選項。

表設置:

create table dbo.Orders (
    OrderID int not null, 
    /* NO Total here */ 
    constraint PK_Orders PRIMARY KEY (OrderID) 
) 
go 
create table dbo.Items (
    ItemID int not null, 
    Cost decimal (19,4) not null, 
    constraint PK_Items PRIMARY KEY (ItemID) 
) 
go 
create table dbo.OrderItems (
    OrderItemID int not null, 
    OrderID int not null, 
    ItemID int not null, 
    /* I'd normally prefer Order/Item/Quantity and making Order/Item the PK */ 
    constraint PK_OrderItems PRIMARY KEY (OrderItemID), 
    constraint FK_OrderItems_Orders FOREIGN KEY (OrderID) references Orders (OrderID), 
    constraint FK_OrderItems_Items FOREIGN KEY (ItemID) references Items (ItemID) 
) 

現在我們可以創建視圖:

create view dbo.OrderTotals 
with schemabinding 
as 
    select 
     OrderID, 
     COUNT_BIG(*) as LineCount, /* Required for indexed view with aggregate */ 
     SUM(Cost) as OrderTotal 
    from 
     dbo.Items i 
      inner join 
     dbo.OrderItems o 
      on 
       i.ItemID = o.ItemID 
    group by 
     OrderID 
go 
create unique clustered index IX_OrderTotals on OrderTotals (OrderID) 

現在,當你執行插入,更新和刪除針對的OrderItems或項目表,這種觀點的指數(其中實際包含所有視圖數據)會自動爲您更新。

這樣可以避免您在使用時可能會漏掉的拐角案件的任何擔憂。觸發器手動執行更新。

相關問題