2017-02-15 51 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或项目表,这种观点的指数(其中实际包含所有视图数据)会自动为您更新。

这样可以避免您在使用时可能会漏掉的拐角案件的任何担忧。触发器手动执行更新。

相关问题