如何获取Update语句以根据另一个表中的条目更改值

时间:2014-11-06 20:16:58

标签: sql-server

我在SQL Server中有一个库存管理数据库。我有四张桌子。物品,销售,订单和地点。

/*Start of Table Creations*/
CREATE TABLE Items
(
    itemID INT,
    itemName VARCHAR(70) NOT NULL,
    quantityOnHand INT CONSTRAINT quantityOnHandCheck CHECK (quantityOnHand >= 0),
    quantityOnOrder INT CONSTRAINT quantityOnOrderCheck CHECK (quantityOnOrder >= 0)

    CONSTRAINT ItemsPK
        PRIMARY KEY (itemID)
)

CREATE TABLE Sales
(
    invoiceID INT,
    itemID INT NOT NULL,
    quantity INT CONSTRAINT salesquantityCheck CHECK (quantity >= 1),
    location INT,
    InvoiceDate DATE

    CONSTRAINT SalesPK
        PRIMARY KEY (invoiceID)
)

CREATE TABLE Orders
(
    orderID INT,
    itemID INT NOT NULL,
    quantity INT CONSTRAINT ordersquantityCheck CHECK (quantity >= 1),
    orderDate DATE,
    delivered VARCHAR(1) CONSTRAINT ordersdeliveredCheck CHECK (delivered = 'Y' OR delivered = 'N')

    CONSTRAINT OrdersPK
        PRIMARY KEY (orderID)
)

CREATE TABLE Locations
(
    locationID INT,
    name VARCHAR(70) NOT NULL,
    address VARCHAR(70),
    street VARCHAR(70),
    city VARCHAR(70),
    province VARCHAR(2),
    country VARCHAR(25) CONSTRAINT countryDefault DEFAULT 'Canada',
    zip VARCHAR(7)

    CONSTRAINT LocationsPK
        PRIMARY KEY (locationID)
)
/*End of Table Creations*/

我有一些插入可以将样本数据插入到这些表中。

/*Insert current Inventory - Start*/
INSERT INTO Items
    (itemID, itemName, quantityOnHand, quantityOnOrder)
VALUES
    (1, 'Mocha Java', 3, 0),
    (2, 'Stevia', 5, 0)
/*Insert current Inventory - End*/

/*Insert current Invoices - Start*/
INSERT INTO Sales
    (invoiceID, itemID, quantity, location, InvoiceDate)
VALUES
    (1, 1, 2, 1, GETDATE()),
    (2, 2, 1, 2, GETDATE())
/*Insert current Invoices - End*/

/*Insert current Orders - Start*/
INSERT INTO Orders
    (orderID, itemID, quantity, orderDate, delivered)
VALUES
    (1, 1, 6, GETDATE(), 'N'),
    (2, 2, 2, GETDATE(), 'N'),
    (3, 1, 6, GETDATE() + 1, 'N')
/*Insert current Orders - End*/

/*Insert current Locations - Start*/
INSERT INTO Locations
    (locationID, name, address, street, city, province, country, zip)
VALUES
    (1, 'CVO', 2106, 'Gordon Street', 'Guelph', 'ON', 'Canada', 'N1L 1G6'),
    (2, 'St John Ambulance (Kitchener Waterloo Branch)', 250, 'Gage Ave', 'Kitchener', 'ON', 'Canada', 'N2M 2C8')
/*Insert current Locations - End*/

然后我有一堆更新声明

/*Update Inventory after a Sale was made - Start*/
UPDATE Items
    SET Items.quantityOnHand = Items.quantityOnHand - Sales.quantity
    FROM Items
    INNER JOIN Sales
    ON Sales.itemID = Items.itemID
/*Update Inventory after a Sale was made - Start*/

/*Update Inventory after an Order was made - Start*/
UPDATE Items
    SET Items.quantityOnOrder = Items.quantityOnOrder + Orders.quantity
    FROM Items
    INNER JOIN Orders
    ON Items.itemID = Orders.itemID
/*Update Inventory after an Order was made - End*/

/*Update Inventory after an Order was delivered - Start*/
UPDATE Items
    SET Items.quantityOnHand = Items.quantityOnHand +  Orders.quantity,
    Items.quantityOnOrder = Items.quantityOnOrder - Orders.quantity
    FROM Items
    INNER JOIN Orders
    ON Orders.itemID = Items.itemID
    WHERE Orders.delivered = 'Y'
/*Update Inventory after an Order was delivered - End*/

最后,我选择语句来反映这些操作。

SELECT * FROM Items

/*SELECT * FROM Items
    WHERE quantityOnHand < 2*/

SELECT Sales.invoiceID, Items.itemName AS 'Item Name', Sales.quantity, Locations.name AS 'Location', DATENAME(mm, Sales.InvoiceDate) + ' ' + DATENAME(dd, Sales.InvoiceDate) + ', ' + DATENAME(yyyy, Sales.InvoiceDate) AS 'Invoice Date'
    FROM Sales
    INNER JOIN Items
    ON Sales.itemID = Items.itemID
    INNER JOIN Locations
    ON Sales.location = Locations.locationID
    ORDER BY Items.itemID ASC

SELECT Orders.OrderID, Items.itemName AS 'Item Name', Orders.quantity, DATENAME(mm, Orders.OrderDate) + ' ' + DATENAME(dd, Orders.OrderDate) + ', ' + DATENAME(yyyy, Orders.OrderDate) AS 'Order Date', Orders.delivered
    FROM Orders
    INNER JOIN Items
    ON Orders.itemID = Items.itemID
    ORDER BY Items.itemID ASC

SELECT locationID, name AS 'Name', address, street, city, province, country, zip
    FROM Locations

在订单表的插入中,我有一个项目的两个订单和相同的数量,但是当运行UPDATE语句时,它只反映其中一个。我在UPDATE语句中使用了INNER JOIN,希望它能将Orders.itemID与Items.itemID匹配,并将适当的数量插入到适当的位置。但不幸的是,而不是它增加了12 ......它只增加了6。

总结中,它以

开头
INSERT INTO Items
    (itemID, itemName, quantityOnHand, quantityOnOrder)
VALUES
    (1, 'Mocha Java', 3, 0),
    (2, 'Stevia', 5, 0)

删除以下

INSERT INTO Sales
    (invoiceID, itemID, quantity, location, InvoiceDate)
VALUES
    (1, 1, 2, 1, GETDATE()),
    (2, 2, 1, 2, GETDATE())

并且应该用

中所有相应记录的SUM更新Items.quantityOnOrder
INSERT INTO Orders
    (orderID, itemID, quantity, orderDate, delivered)
VALUES
    (1, 1, 6, GETDATE(), 'N'),
    (2, 2, 2, GETDATE(), 'N'),
    (3, 1, 6, GETDATE(), 'N')

使用

UPDATE Items
    SET Items.quantityOnOrder = Items.quantityOnOrder + Orders.quantity
    FROM Items
    INNER JOIN Orders
    ON Items.itemID = Orders.itemID

第1项的QuantityOnOrder应为12,但它显示为6。

我希望我很容易理解,因为它有很多:)

任何帮助都将非常感谢!!!

1 个答案:

答案 0 :(得分:1)

这里有一些问题。我看到的主要是数据建模。您似乎将相同的信息存储在两个不同的位置,即Items.quantityOnOrderOrders.quantity。除非性能或其他限制禁止这样做,否则最好直接从Orders获得订单数量值:

SELECT i.itemID, COALESCE(SUM(o.quantity), 0) AS quantityOnOrder
FROM   Items i
LEFT JOIN Orders o ON i.itemID = o.itemID
GROUP BY i.itemID

如果您确实认为必须将数量存储在Items表中,则可能需要使用Orders表中的总和更新该数量:

;WITH Quantities AS
(
    SELECT i.itemID, COALESCE(SUM(o.quantity), 0) AS quantity
    FROM   Items i
    LEFT JOIN Orders o ON i.itemID = o.itemID
    GROUP BY o.itemID
)
UPDATE Items
SET    Items.quantityOnOrder = q.quantity
FROM   Quantities q
WHERE  Items.itemID = q.itemID

进一步优化是可能的,但我希望这能指出你正确的方向。

修改

作为对Items.quantityOnHandOrders.delivered更改delivered时作者的评论的回应,似乎有必要探索CREATE TRIGGER DeliveryTrigger ON Orders AFTER INSERT, UPDATE AS UPDATE Items SET quantityOnHand = Items.quantityOnHand - upd.quantity FROM (SELECT i.itemID, SUM(i.quantity) AS quantity FROM inserted i LEFT JOIN deleted d ON i.orderID = d.orderID WHERE i.delivered = 'Y' AND (d.delivered IS NULL OR d.delivered = 'N') GROUP BY i.itemID) upd WHERE Items.itemID = upd.itemID 可以设置的可能方式。最终,一个好的解决方案在很大程度上取决于业务规则和其他约束。

例如,如果您的环境中鼓励使用触发器,则可以尝试:

CREATE PROCEDURE DeliverOrder
    @orderID INT
AS
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION

IF EXISTS (SELECT 1 FROM Orders o
           WHERE  o.orderID = @orderID
           AND    o.delivered = 'N')
BEGIN
    UPDATE Orders
    SET    delivered = 'Y'
    WHERE  orderID = @orderID

    UPDATE Items
    SET    quantityOnHand = Items.quantityOnHand - o.quantity
    FROM   Orders o
    WHERE  Items.itemID = o.itemID
    AND    o.orderID = @orderID
END
COMMIT TRANSACTION

然而,在存储过程中处理此逻辑可能会更好,例如:

{{1}}

当然,您可能需要根据您的具体操作,确切地说您的业务规则等来修改这些语句。