外热呃 发表于 2014-11-7 10:36:18

sql server 2012 merge的使用,同构表merger,异构表merge, 当merge 与trigger 同时使用时较容易出错

    Create Trigger trMergeProductSummary on ProductDetails
   After Insert, Update, Delete
    AS
    BEGIN
      
    ;Merge ProductSummary
    Using (
   SELECT
      i.ProductId,
      i.ProductName,
      i.ProductNumber,
      i.CategoryId,
      i.ContactPerson,
      i.UpdateDate
   from inserted i
    ) MergeData ON ProductSummary.ProductId = MergeData.ProductId
   WHEN MATCHED THEN
   UPDATE SET
      ProductSummary.ProductName = MergeData.ProductName,
      ProductSummary.ProductNumber = MergeData.ProductNumber,
      ProductSummary.CategoryId = MergeData.CategoryId,
      ProductSummary.ContactPerson = MergeData.ContactPerson,
      ProductSummary.UpdateDate = GetDate()
   WHEN NOT MATCHED BY TARGET THEN
   INSERT VALUES (ProductId, ProductName, ProductNumber, CategoryId, ContactPerson, GetDate())
   WHEN NOT MATCHED BY SOURCE THEN DELETE;
      
    END
    GO


当运行下面语句时,ProductSummary只有一条记录:而不是我们期望的三条



    insert into ProductDetails (productname, productnumber, contactperson)
   values ('SQL Data Compare Tool', 'SQL-DC-001', 'Eralper Yilmaz')
   go 3
    select * from ProductDetails
    select * from ProductSummary

只有一条记录:而不是我们期望的三条

当运行下面语句时,ProductSummary 只有一条记录:而不是我们期望的三条

当运行下面语句时,ProductSummary 中的数据被消除:
注意,
当delete时trigger 中的inserted没有数据,所以会清空ProductSummary 表:
WHEN NOT MATCHED BY SOURCE THEN DELETE--source is empty, so it will clear all data in table ProductSummary

下面是merge trigger 的实现
    IF OBJECT_ID('.', 'TR') IS NOT NULL
    BEGIN
      DROP TRIGGER .
    END
    GO   
    CREATE TRIGGER .
    ON .
    FORINSERT, DELETE, UPDATE
    AS
    set nocount on
    DECLARE @count      BIGINT = 0,
            @rowid      BIGINT = 1,   
            @sql          NVARCHAR(MAX) = N'',
            @sqlmerge   NVARCHAR(3000) = N'',   
            @action       NVARCHAR(20)='',
            @RECID      BIGINT   
    if exists(select 1 from tempdb..sysobjects where id=object_id('tempdb..#tmp'))
      DROP TABLE #tmp
    IF EXISTS(SELECT * FROM   INSERTED) AND NOT EXISTS(SELECT * FROM   DELETED) ----INSERT
    BEGIN
            SET @action='INSERT'
    END      
    ELSE IF NOT EXISTS(SELECT * FROM   INSERTED)AND EXISTS(SELECT * FROM   DELETED) ----DELETE
    BEGIN
         SET @action='DELETE'
    END
    ELSE IF EXISTS(SELECT * FROM   INSERTED) AND EXISTS(SELECT * FROM   DELETED) -----UPDATE
    BEGIN
         SET @action='UPDATE'
    END
    SELECT row_number()OVER(ORDER BY dataareaid) rowid,DESCRIPTION,cast (code as nvarchar)code,category,GETDATE() Modifieddatetime,Modifiedby,GETDATE() Createddatetime,CreatedBy,dataareaid,1 Recversion,cast(0.0 as bigint) Recid ,@ACTION AS INTO #tmp FROM inserted
         
    SELECT @count=@@rowcount
    IF @action<>'DELETE' ----INSERT
    BEGIN      
    If @action='INSERT'      
    WHILE @rowid<=@count
      BEGIN   
            EXECDBO.UP_Get_Axapta_Seqno 'AvSysCodesAX',@RECID OUTPUT
            UPDATE #tmp SET recid=@recid WHERE rowid=@rowid
            SET @rowid+=1
      END      
      
      
    ;MERGE dbo.AvSysCodesAX d USING#tmp s   
            ON d.dataareaid = s.dataareaid AND d.category = s.category ANDd.code = s.code         
            WHEN NOT matchedTHEN   
            INSERT ( DESCRIPTION,code,category,Modifieddatetime,Modifiedby,Createddatetime,CreatedBy,dataareaid, Recversion,Recid)VALUES   
             ( S.DESCRIPTION,S.code,S.category,S.Modifieddatetime,S.Modifiedby,S.Createddatetime,S.CreatedBy,S.dataareaid,S.Recversion,S.Recid)   
            WHEN matched AND S.='UPDATE' THEN      
            UPDATE    SET            
               d.    = s. ,   
               d.code                = s.code,   
               d.category            = s.category,   
               d.Modifieddatetime    = s.Modifieddatetime,   
               d.Modifiedby      = s.Modifiedby,   
               d.dataareaid      = s.dataareaid   ;
    END
    else
    begin
      delete d from dbo.AvSysCodesAX d where exists(
            select 1 from deleted swhere d.dataareaid = s.dataareaid AND d.category = s.category ANDd.code = s.code      
      )
    end
      
      
    if exists(select 1 from tempdb..sysobjects where id=object_id('tempdb..#tmp'))
    DROP TABLE #tmp   
    GO   

注意三点:

    merge的源是第一次触发的inserted和deleted,这点不同于物理表,datasource 用inserted union deleted
    在WHENmatched AND S.ACTION='DELETE' THEN delete;
    没有trigger row by row,seem currsor as the last choice.

存用



页: [1]
查看完整版本: sql server 2012 merge的使用,同构表merger,异构表merge, 当merge 与trigger 同时使用时较容易出错