MS SQL使一个表的列依赖于其他表值和

时间:2017-02-15 07:47:10

标签: sql sql-server sql-server-2008

我有一张桌子"订单"像这样,它包含有关订单的信息。

Order ID | ... | Order Total

然而,订单包括几个项目,还有一个"项目订单"表:

Item Order ID | Order ID | Item ID

" Item"表:

Item ID | Cost

因此,订单< - >项目订单具有一对多关系,并且项目订单< - >物品有多对一的关系。

逻辑上,订单总额应取决于其中每个商品订单的成本,这会将商品的成本添加到总计。

如何设置依赖关系,订单总额取决于与此订单对应的所有项目订单,并总结所有需要的项目成本?我想每次在订单中添加新的商品订单时也应该更新。

2 个答案:

答案 0 :(得分: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或Items表执行插入,更新和删除时,此视图的索引(实际上包含所有视图数据)会自动为您更新。

这可以避免任何关于角落情况的担忧,如果您使用例如触发器手动执行更新。

答案 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