我在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.quantityOnOrderINSERT 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。
我希望我很容易理解,因为它有很多:)
任何帮助都将非常感谢!!!
答案 0 :(得分:1)
这里有一些问题。我看到的主要是数据建模。您似乎将相同的信息存储在两个不同的位置,即Items.quantityOnOrder
和Orders.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.quantityOnHand
值Orders.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}}
当然,您可能需要根据您的具体操作,确切地说您的业务规则等来修改这些语句。