我可以将此触发器缩短/更好/更快吗?

时间:2015-06-10 11:16:13

标签: sql-server

任务本身非常基础。我有一个交易表,可以将一定数量的产品移入或移出库存。知道产品可以由多个“基础”产品组成,只有基础产品可能存在于库存中,这变得有点困难。

我当前的触发器有效但工作方式如下:

  1. 创建可以组合插入,删除和组合产品的临时表。
  2. 将插入的非组合产品添加到此临时表
  3. 添加插入的合成产品
  4. 减去已删除的非组合产品
  5. 减去已删除的撰写产品
  6. 我现在有一个包含非组合产品的所有交易的表格。但是,即更新一行,相同的产品会被添加两次。一旦减去旧值并添加新值。

    1. 为已加入的非组合产品创建第二个临时表
    2. 获取产品的总和并将它们放入新的临时表
    3. 将库存与此临时表合并
    4. 再次..我的触发器工作正常,我没有性能问题(但)我觉得我错过了什么。我打赌这里有人有一个比我更好的解决方案。

      我的表格和示例数据:(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
      

0 个答案:

没有答案