任务本身非常基础。我有一个交易表,可以将一定数量的产品移入或移出库存。知道产品可以由多个“基础”产品组成,只有基础产品可能存在于库存中,这变得有点困难。
我当前的触发器有效但工作方式如下:
我现在有一个包含非组合产品的所有交易的表格。但是,即更新一行,相同的产品会被添加两次。一旦减去旧值并添加新值。
再次..我的触发器工作正常,我没有性能问题(但)我觉得我错过了什么。我打赌这里有人有一个比我更好的解决方案。
我的表格和示例数据:(fiddle here)
CREATE TABLE [dbo].[Product](
[id] [int] IDENTITY(1,1) NOT NULL,
[plantId] [int] NOT NULL,
[reference] [nvarchar](50) NOT NULL,
[composed] [bit] NOT NULL DEFAULT ((0)),
[name] [nvarchar](max) NOT NULL,
[unit] [nvarchar](50) NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate())
);
INSERT INTO [dbo].[Product] VALUES (2, 'FILLER VULPROF 2 BR', 0, 'FILLER VULPROF 2 BR', 'ton', GETDATE());
INSERT INTO [dbo].[Product] VALUES (2, 'K 0/2GEW BR', 0, 'K 0/2GEW BR', 'ton', GETDATE());
INSERT INTO [dbo].[Product] VALUES (2, 'K 14/20 BR', 0, 'K 14/20 BR', 'ton', GETDATE());
INSERT INTO [dbo].[Product] VALUES (2, 'KWS BR 3A31', 1, 'KWS BR 3A31', 'ton', GETDATE());
CREATE TABLE [dbo].[ProductComposition](
[id] [int] IDENTITY(1,1) NOT NULL,
[productId] [int] NOT NULL,
[parentId] [int] NOT NULL, -- This is the parent product
[quantity] [float] NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate())
);
INSERT INTO [dbo].[ProductComposition] VALUES (1, 4, 0.001, GETDATE());
INSERT INTO [dbo].[ProductComposition] VALUES (3, 4, 0.001, GETDATE());
CREATE TABLE [dbo].[Transaction](
[id] [int] IDENTITY(1,1) NOT NULL,
[load] [bit] NOT NULL,
[plantId] [int] NOT NULL,
[vehicleId] [int] NOT NULL,
[productId] [int] NOT NULL,
[contactId] [int] NOT NULL,
[quantity] [float] NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate()),
[isSynched] [bit] NOT NULL CONSTRAINT [DF_Transaction_isSynched] DEFAULT ((0))
);
CREATE TABLE [dbo].[Stock](
[id] [int] IDENTITY(1,1) NOT NULL,
[plantId] [int] NOT NULL,
[productId] [int] NOT NULL,
[quantity] [float] NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate())
);
我的触发器:
ALTER TRIGGER [dbo].[StockCalculate]
ON [dbo].[Transaction]
AFTER INSERT, UPDATE, DELETE AS
BEGIN
-- Create temporary table
CREATE TABLE #TransactionsComposed (
[load] [bit] NOT NULL,
[plantId] [int] NOT NULL,
[productId] [int] NOT NULL,
[quantity] [float] NOT NULL
);
-- Insert basic materials
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
[Inserted].[load],
[Inserted].[plantId],
[Inserted].[productId],
[Inserted].[quantity]
FROM
[Inserted]
INNER JOIN [Product] ON [Product].[id] = [Inserted].[productId]
WHERE
[Product].[composed] = 0;
-- Insert operations
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
[Inserted].[load],
[Inserted].[plantId],
[ProductComposition].[productId],
([Inserted].[quantity] * [ProductComposition].[quantity])
FROM
[Inserted]
INNER JOIN [Product] ON [Product].[id] = [Inserted].[productId]
INNER JOIN [ProductComposition] ON [ProductComposition].[parentId] = [Product].[id]
WHERE
[Product].[composed] = 1;
-- Insert basic materials but ALTER it's load status.
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
CASE [Deleted].[load]
WHEN 0 THEN 1
WHEN 1 THEN 0
END,
[Deleted].[plantId],
[Deleted].[productId],
[Deleted].[quantity]
FROM
[Deleted]
INNER JOIN [Product] ON [Product].[id] = [Deleted].[productId]
WHERE
[Product].[composed] = 0;
-- Insert operations but ALTER it's load status.
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
CASE [Deleted].[load]
WHEN 0 THEN 1
WHEN 1 THEN 0
END,
[Deleted].[plantId],
[ProductComposition].[productId],
([Deleted].[quantity] * [ProductComposition].[quantity])
FROM
[Deleted]
INNER JOIN [Product] ON [Product].[id] = [Deleted].[productId]
INNER JOIN [ProductComposition] ON [ProductComposition].[parentId] = [Product].[id]
WHERE
[Product].[composed] = 1;
-- Prepare multiple products for merge
CREATE TABLE #TransactionsJoined (
[plantId] [int] NOT NULL,
[productId] [int] NOT NULL,
[quantity] [float] NOT NULL
);
INSERT INTO #TransactionsJoined
([plantId], [productId], [quantity])
SELECT
[plantId],
[productId],
SUM(CASE [load]
WHEN 0 THEN [quantity]
WHEN 1 THEN 0 - [quantity]
END)
FROM
#TransactionsComposed
GROUP BY [plantId], [productId]
-- Merge composed transactions into the stock
MERGE [Stock]
USING #TransactionsJoined
ON [Stock].[plantId]=#TransactionsJoined.[plantId]
AND [Stock].[productId]=#TransactionsJoined.[productId]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([plantId], [productId], [quantity])
VALUES (
#TransactionsJoined.[plantId],
#TransactionsJoined.[productId],
#TransactionsJoined.[quantity])
WHEN MATCHED THEN
UPDATE SET
[Stock].[quantity] = [Stock].[quantity] + #TransactionsJoined.[quantity],
[Stock].[dateUpdate] = GETDATE();
END