我如何将 Insert 从 select 转换为 upsert

How can i convert Insert from select to upsert

如何将插入从 select 转换为更新插入。我有以下代码将数据从一个数据库 table 插入到另一个数据库,我能够插入到但如果某些内容更改了不属于 PK 的任何字段。 WITESTCO.dbo.[WIBOMD] 的主键是 [bomItem], [bomRev], [bomEntry]

INSERT INTO WITESTCO.dbo.[WIBOMD] 
   ([bomItem], [bomRev], [bomEntry], [partId], [qty],[cmnt],[srcLoc],[dType],[lead],[lineNbr])
   select 
    [STOCK NO]    
  , u.rev
  , bomEntry = row_number() over (order by u.ordinal)
  , u.Partid
  , Qty='1'
  , cmnt = 'TEST'
  , srcLoc = 'TEST'
  , dType = '0'
  , lead = '0'
  , lineNbr = row_number() over (order by u.ordinal)
from [inserted]
  cross apply (values 
    ([bomRev],1,[BOM-WHEEL PN])
    ,([bomRev],2,[BOM - RIM])
    ,([bomRev],3,[BOM - SECONDARY DISC PN])
    ,([bomRev],4,[BOM - FIN DISC PN])
    ,([bomRev],5, [BOM - FLAT FIN DISC PN])
    ,([bomRev],6,[WHL BOM PART 1 PN])
    ,([bomRev],7,[WHL BOM PART 2 PN])
    ,([bomRev],8,[WHL BOM PART 3 PN])
    ,([bomRev],9,[WHL BOM PART 4 PN])
    ,([bomRev],10,[WHL BOM PART 5 PN])
    ,([bomRev],11,[COLOR-PN])

) u (rev, ordinal, partId)
where nullif(u.partId,'') is not null AND  NOT EXISTS(SELECT * FROM  WITESTCO.dbo.[WIBOMD] WHERE WITESTCO.dbo.[WIBOMD].[bomItem]=inserted.[STOCK NO] and WITESTCO.dbo.[WIBOMD].[bomRev]=inserted.[RevControl]);

使用 common table expression 这样我们就可以在 not exists():

中包含 bomEntry
;with cte as (
   select 
    [STOCK NO]    
  , u.rev
  , bomEntry = row_number() over (order by u.ordinal)
  , u.Partid
  , Qty='1'
  , cmnt = 'TEST'
  , srcLoc = 'TEST'
  , dType = '0'
  , lead = '0'
  , lineNbr = row_number() over (order by u.ordinal)
  , RevControl
from [inserted]
  cross apply (values 
     ([bomRev],1,[BOM-WHEEL PN])
    ,([bomRev],2,[BOM - RIM])
    ,([bomRev],3,[BOM - SECONDARY DISC PN])
    ,([bomRev],4,[BOM - FIN DISC PN])
    ,([bomRev],5, [BOM - FLAT FIN DISC PN])
    ,([bomRev],6,[WHL BOM PART 1 PN])
    ,([bomRev],7,[WHL BOM PART 2 PN])
    ,([bomRev],8,[WHL BOM PART 3 PN])
    ,([bomRev],9,[WHL BOM PART 4 PN])
    ,([bomRev],10,[WHL BOM PART 5 PN])
    ,([bomRev],11,[COLOR-PN])
  ) u (rev, ordinal, partId)
where nullif(u.partId, '') is not null 
)

INSERT INTO WITESTCO.dbo.[WIBOMD] 
   ([bomItem], [bomRev], [bomEntry], [partId], [qty],[cmnt],[srcLoc],[dType],[lead],[lineNbr])
   select 
    cte.[STOCK NO]
  , cte.rev
  , cte.bomEntry
  , cte..Partid
  , cte.Qty
  , cte.cmnt
  , cte.srcLoc
  , cte.dType
  , cte.lead
  , cte.lineNbr
from cte
where not exists (
    select 1
    from WITESTCO.dbo.[WIBOMD] w
    where w.[bomItem] = cte.[STOCK NO]
      and w.[bomRev]  = cte.[RevControl]
      and w.[bomEntry]= cte.bomEntry
  );

或者,您可以使用 subquery/derived table 代替常见的 table 表达式。

如果您使用的是 sql server 2008+,则可以使用 MERGE 语句 https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql

我在为您实施它时遇到了困难,但如果没有模式或不清楚您的数据是什么样子,这个解决方案第一次不太可能奏效。请更多地使用它作为概念证明而不是完全工作的代码。

MERGE WITESTCO.dbo.[WIBOMD] AS target  
USING ( SELECT [STOCK NO]    
              , u.rev
              , bomEntry  = row_number() over (order by u.ordinal)
              , u.Partid
              , Qty       ='1'
              , cmnt      = 'TEST'
              , srcLoc    = 'TEST'
              , dType     = '0'
              , lead      = '0'
              , lineNbr   = row_number() over (order by u.ordinal)
        FROM  [inserted]
              CROSS APPLY ( VALUES  ([bomRev],1,[BOM-WHEEL PN])
                                  , ([bomRev],2,[BOM - RIM])
                                  , ([bomRev],3,[BOM - SECONDARY DISC PN])
                                  , ([bomRev],4,[BOM - FIN DISC PN])
                                  , ([bomRev],5, [BOM - FLAT FIN DISC PN])
                                  , ([bomRev],6,[WHL BOM PART 1 PN])
                                  , ([bomRev],7,[WHL BOM PART 2 PN])
                                  , ([bomRev],8,[WHL BOM PART 3 PN])
                                  , ([bomRev],9,[WHL BOM PART 4 PN])
                                  , ([bomRev],10,[WHL BOM PART 5 PN])
                                  , ([bomRev],11,[COLOR-PN]) ) u (rev, ordinal, partId )
        WHERE   NULLIF(u.partId,'') is NOT NULL 
          AND   NOT EXISTS ( SELECT  * 
                             FROM    WITESTCO.dbo.[WIBOMD] 
                             WHERE   WITESTCO.dbo.[WIBOMD].[bomItem] = inserted.[STOCK NO] 
                               AND   WITESTCO.dbo.[WIBOMD].[bomRev]  = inserted.[RevControl] ) 
        ) AS source ( [STOCK NO], rev, bomEntry, Partid, Qty, cmnt, srcLoc, dType, lead, lineNbr )
    ON  ( target.bomItem  = source.[STOCK NO] 
          target.bomRev   = source.Rev 
          target.bomEntry = source.bomEntry )  
WHEN MATCHED THEN   
    UPDATE  [bomItem]  =  [STOCK NO] 
          , [bomRev]   =  u.rev
          , [bomEntry] =  bomEntry  
          , [partId]   =  Partid
          , [qty]      =  Qty       
          , [cmnt]     =  cmnt      
          , [srcLoc]   =  srcLoc    
          , [dType]    =  dType     
          , [lead]     =  lead      
          , [lineNbr]  =  lineNbr   
WHEN NOT MATCHED THEN  
    INSERT ([bomItem], [bomRev], [bomEntry], [partId], [qty], [cmnt], [srcLoc], [dType], [lead], [lineNbr])  
    VALUES ([STOCK NO], rev,     bomEntry,   Partid,   Qty,   cmnt,   srcLoc,   dType,   lead,   lineNbr  )