首页 > Linux操作系统 > Linux操作系统 > 利用MERGE刷新库存快照
SQL Server 2008中有一个新的语法叫做MERGE,这种语法可以融合UPDATE、DELETE和INSERT。特别适合于将交易型的记录集合并到快照性的结果集中去。非常具有代表性的应用场景就是库存管理,库存管理应用(俗称进销存)中经常需要获得某个时间点上的库存,也称为库存结余。
讨论一下一些基础的东西,在数据库建模中有两种基本模型:
因此一般我们都会用混合模型,为了保证历史的可追溯,进出仓的事务明细是一定要保留的(至少在一段时间内),而为了满足对库存结余查询的及时性和性能则需要维护一张快照表,并且保证定期更新这张快照表。为了保证性能并满足应用的逻辑弹性,这些混和模型的设计是相当重要的,也就是如何更新快照表,不过在这里我们就不多说了。
在评估SQL Server 2008的过程中,我把SQL Server 2008联机丛书里面的代码给改了一下,一是更加贴和应用的实际情况,二是联机丛书的MERGE范例只合并了UPDATE和DELETE,我多加了一个INSERT的情况。:)
在这里和大家共享一下修改后的代码:
--Step 1: Create test table
USE tempdb
GO
CREATE TABLE Inventory_Snapshot
(
ProductID int PRIMARY KEY NOT NULL,
Quantity int NOT NULL
)
GO
CREATE TABLE Inventory_Operation
(
OperationID int PRIMARY KEY IDENTITY(1,1),
OperationDate datetime,
OperationType int, --1:Move in; 2:Move out; 3:Adjustment
ProductID int,
Quantity int
)
GO
--Step 2: Create stored procedure for new inventory operation
CREATE PROCEDURE usp_Inventory_Operation
@productID int,
@operationDate datetime,
@operationType int, --1:Move in; 2:Move out; 3:Adjustment
@quantity int
AS
INSERT INTO Inventory_Operation
(OperationDate, OperationType, ProductID, Quantity)
VALUES
(@operationDate, @operationType, @productID, @quantity)
GO
--Step 3: Create stored procedure for inventory snapshot calculation
CREATE PROCEDURE usp_Inventory_Snapshot_Process
@processDate datetime
AS
MERGE Inventory_Snapshot AS invs
USING (SELECT ProductID, Sum(ABSQuantity) AS SubTotal
FROM (SELECT ProductID, Quantity *
CASE OperationType --1:Move in; 2:Move out; 3:Adjustment
WHEN 1 THEN 1
WHEN 2 THEN -1
WHEN 3 THEN 1
ELSE 0
END AS ABSQuantity FROM Inventory_Operation
WHERE perationDate = @processDate) AggInvo
GROUP BY AggInvo.ProductID)
AS invo(ProductID, SubTotal)
ON (invs.ProductID = invo.ProductID)
WHEN MATCHED AND invs.Quantity <> invo.SubTotal AND invs.Quantity <> invo.SubTotal * -1
THEN UPDATE SET invs.Quantity = invs.Quantity + invo.SubTotal
WHEN MATCHED AND invs.Quantity = invo.SubTotal * -1
THEN DELETE
WHEN TARGET NOT MATCHED
THEN INSERT VALUES (invo.ProductID, invo.SubTotal);
GO
DELETE FROM dbo.Inventory_Snapshot
--Step 4: Test application logic
--2007-1-1
EXEC usp_Inventory_Operation 1000, '2007-1-1', 1, 500
EXEC usp_Inventory_Operation 1001, '2007-1-1', 1, 300
EXEC usp_Inventory_Operation 1002, '2007-1-1', 1, 250
EXEC usp_Inventory_Snapshot_Process '2007-1-1'
SELECT * FROM Inventory_Snapshot
GO
EXEC usp_Inventory_Operation 1001, '2007-1-2', 2, 200
EXEC usp_Inventory_Operation 1003, '2007-1-2', 1, 300
EXEC usp_Inventory_Operation 1000, '2007-1-2', 2, 200
EXEC usp_Inventory_Snapshot_Process '2007-1-2'
SELECT * FROM Inventory_Snapshot
GO
EXEC usp_Inventory_Operation 1000, '2007-1-3', 2, 200
EXEC usp_Inventory_Operation 1002, '2007-1-3', 2, 250
EXEC usp_Inventory_Operation 1004, '2007-1-3', 2, 300
EXEC usp_Inventory_Snapshot_Process '2007-1-3'
SELECT * FROM Inventory_Snapshot
GO
最后需要说明的是,通常DBA或者开发员都会认为交易型记录一旦写入数据库后就不会修改,但实际上不是的。我就在一家大型物流公司中见过某些库存操作会找一条记录直接更新(实际上是锁仓操作,这种设计的初衷可能是考虑到锁仓操作非常频繁的缘故吧,不管怎么样,直接更新交易型记录的情况确实存在)。
就像上面的范例代码一样,如果我们对2007年1月2日的进出仓明细记录执行过了usp_Inventory_Snapshot_Process处理后2007年1月2日的交易记录又被修改了,这个时候怎么办呢?......这或许就是数据库架构设计迷人之处吧......
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9079672/viewspace-159336/ ,如需转载,请注明出处,否则将追究法律责任。