2016-06-20 12 views
2

Ich habe auf der MERGE-Syntax in SQL Server gelesen und es ist perfekt für das, was ich tun muss, aber ich kann nicht für das Leben von mir herausfinden wie verhindert werden kann, dass die Zieltabelle alte Daten löscht, denen ich nicht zuordnen möchte.SQL Server Merge, wie Subset Ziel nach Datumsbereich (Jahr)

Ich habe 11 Millionen Zeilen in Ziel, und ich möchte nur das aktuelle Jahr für Änderungen entsprechen, die ~ 300k Reihen ist. Offensichtlich wird es massive Leistungsunterschiede geben.

Mein Code:

MERGE [dbo].[RE_Gifts_Backup_testing] as Target --[TARGET is main table] 
    USING [dbo].[RE_Gifts_CY_Changes] as Source --[SOURCE is data with new changes] 

    ON (Target.gift_id = Source.gift_id) -- What are we matching rows on. 




    --When rows are matched, update the records if there is any change 

    WHEN MATCHED 
      AND year(Target.gift_date) = '2016' 
      AND year(Source.Gift_Date) = '2016' 
      AND (TARGET.[Constituent_ID] <> SOURCE.[Constituent_ID] 
      OR TARGET.[RE_Gift_ID] <> SOURCE.[RE_Gift_ID] 
      OR TARGET.[Gift_ID] <> SOURCE.[Gift_ID] 
      OR TARGET.[Gift_Date_Added] <> SOURCE.[Gift_Date_Added] 
      OR TARGET.[Gift_Date] <> SOURCE.[Gift_Date] 
      OR TARGET.[Name] <> SOURCE.[Name] 
      OR TARGET.[Gift_Type] <> SOURCE.[Gift_Type] 
      OR TARGET.[Gift_Amount] <> SOURCE.[Gift_Amount] 
      OR TARGET.[Frequency] <> SOURCE.[Frequency] 
      OR TARGET.[Pay_Method] <> SOURCE.[Pay_Method] 
      OR TARGET.[Appeal] <> SOURCE.[Appeal] 
      OR TARGET.[Campaign] <> SOURCE.[Campaign] 
      OR TARGET.[Gift Added By] <> SOURCE.[Gift Added By] 
      OR TARGET.[Gift Reference] <> SOURCE.[Gift Reference] 
      OR TARGET.[SoftCredit] <> SOURCE.[SoftCredit] 
      OR TARGET.[Relationship Manager] <> SOURCE.[Relationship Manager] 
      OR TARGET.[CostCentre] <> SOURCE.[CostCentre] 
      OR TARGET.[Recruiter] <> SOURCE.[Recruiter] 
      OR TARGET.[Sitecode] <> SOURCE.[Sitecode] 
      OR TARGET.[Zerodebit] <> SOURCE.[Zerodebit] 
      OR TARGET.[Donation_Channel] <> SOURCE.[Donation_Channel] 
      OR TARGET.[Source_Channel] <> SOURCE.[Source_Channel] 
      OR TARGET.[Recruitment_Source] <> SOURCE.[Recruitment_Source] 
      OR TARGET.[Merch_ProductID] <> SOURCE.[Merch_ProductID]) 


     THEN UPDATE 
      set 
       TARGET.[Constituent_ID] = SOURCE.[Constituent_ID], 
       TARGET.[RE_Gift_ID] = SOURCE.[RE_Gift_ID], 
       TARGET.[Gift_ID] = SOURCE.[Gift_ID], 
       TARGET.[Gift_Date_Added] = SOURCE.[Gift_Date_Added], 
       TARGET.[Gift_Date] = SOURCE.[Gift_Date], 
       TARGET.[Name] = SOURCE.[Name], 
       TARGET.[Gift_Type] = SOURCE.[Gift_Type], 
       TARGET.[Gift_Amount] = SOURCE.[Gift_Amount], 
       TARGET.[Frequency] = SOURCE.[Frequency], 
       TARGET.[Pay_Method] = SOURCE.[Pay_Method], 
       TARGET.[Appeal] = SOURCE.[Appeal], 
       TARGET.[Campaign] = SOURCE.[Campaign], 
       TARGET.[Gift Added By] = SOURCE.[Gift Added By], 
       TARGET.[Gift Reference] = SOURCE.[Gift Reference], 
       TARGET.[SoftCredit] = SOURCE.[SoftCredit], 
       TARGET.[Relationship Manager] = SOURCE.[Relationship Manager], 
       TARGET.[CostCentre] = SOURCE.[CostCentre], 
       TARGET.[Recruiter] = SOURCE.[Recruiter], 
       TARGET.[Sitecode] = SOURCE.[Sitecode], 
       TARGET.[Zerodebit] = SOURCE.[Zerodebit], 
       TARGET.[Donation_Channel] = SOURCE.[Donation_Channel], 
       TARGET.[Source_Channel] = SOURCE.[Source_Channel], 
       TARGET.[Recruitment_Source] = SOURCE.[Recruitment_Source], 
       TARGET.[Merch_ProductID] = SOURCE.[Merch_ProductID] 

    -- when no records are matched then insert from source into target. 
    WHEN NOT MATCHED BY TARGET and year(target.gift_date) >= '2016' THEN 

    INSERT ([Constituent_ID],[RE_Gift_ID],[Gift_ID],[Gift_Date_Added],[Gift_Date],[Name],[Gift_Type],[Gift_Amount],[Frequency],[Pay_Method],[Appeal],[Campaign],[Gift Added By],[Gift Reference], 
       [SoftCredit],[Relationship Manager],[CostCentre],[Recruiter],[Sitecode],[Zerodebit],[Donation_Channel],[Source_Channel],[Recruitment_Source],[Merch_ProductID]) 

    VALUES (source.[Constituent_ID],source.[RE_Gift_ID],source.[Gift_ID],source.[Gift_Date_Added],source.[Gift_Date],source.[Name],source.[Gift_Type],source.[Gift_Amount],source.[Frequency], 
       source.[Pay_Method],source.[Appeal],source.[Campaign],source.[Gift Added By],source.[Gift Reference],source.[SoftCredit],source.[Relationship Manager],source.[CostCentre], 
       source.[Recruiter],source.[Sitecode],source.[Zerodebit],source.[Donation_Channel],source.[Source_Channel],source.[Recruitment_Source],source.[Merch_ProductID]) 

    --When there is a row that exists in target table and same record does not exist in source table then delete this record from target table 
    WHEN NOT MATCHED BY SOURCE and year(target.gift_date) >= '2016' THEN 
    DELETE 

    OUTPUT $action, 
      deleted.[Constituent_ID] as [deletedConstituent_ID], 
      deleted.[RE_Gift_ID] as [deletedRE_Gift_ID], 
      deleted.[Gift_ID] as [deletedGift_ID], 
      deleted.[Gift_Date_Added] as [deletedGift_Date_Added], 
      deleted.[Gift_Date] as [deletedGift_Date], 
      deleted.[Name] as [deletedName], 
      deleted.[Gift_Type] as [deletedGift_Type], 
      deleted.[Gift_Amount] as [deletedGift_Amount], 
      deleted.[Frequency] as [deletedFrequency], 
      deleted.[Pay_Method] as [deletedPay_Method], 
      deleted.[Appeal] as [deletedAppeal], 
      deleted.[Campaign] as [deletedCampaign], 
      deleted.[Gift Added By] as [deletedGift Added By], 
      deleted.[Gift Reference] as [deletedGift Reference], 
      deleted.[SoftCredit] as [deletedSoftCredit], 
      deleted.[Relationship Manager] as [deletedRelationship Manager], 
      deleted.[CostCentre] as [deletedCostCentre], 
      deleted.[Recruiter] as [deletedRecruiter], 
      deleted.[Sitecode] as [deletedSitecode], 
      deleted.[Zerodebit] as [deletedZerodebit], 
      deleted.[Donation_Channel] as [deletedDonation_Channel], 
      deleted.[Source_Channel] as [deletedSource_Channel], 
      deleted.[Recruitment_Source] as [deletedRecruitment_Source], 
      deleted.[Merch_ProductID] as [deletedMerch_ProductID], 

      inserted.[Constituent_ID] as [insertedConstituent_ID], 
      inserted.[RE_Gift_ID] as [insertedRE_Gift_ID], 
      inserted.[Gift_ID] as [insertedGift_ID], 
      inserted.[Gift_Date_Added] as [insertedGift_Date_Added], 
      inserted.[Gift_Date] as [insertedGift_Date], 
      inserted.[Name] as [insertedName], 
      inserted.[Gift_Type] as [insertedGift_Type], 
      inserted.[Gift_Amount] as [insertedGift_Amount], 
      inserted.[Frequency] as [insertedFrequency], 
      inserted.[Pay_Method] as [insertedPay_Method], 
      inserted.[Appeal] as [insertedAppeal], 
      inserted.[Campaign] as [insertedCampaign], 
      inserted.[Gift Added By] as [insertedGift Added By], 
      inserted.[Gift Reference] as [insertedGift Reference], 
      inserted.[SoftCredit] as [insertedSoftCredit], 
      inserted.[Relationship Manager] as [insertedRelationship Manager], 
      inserted.[CostCentre] as [insertedCostCentre], 
      inserted.[Recruiter] as [insertedRecruiter], 
      inserted.[Sitecode] as [insertedSitecode], 
      inserted.[Zerodebit] as [insertedZerodebit], 
      inserted.[Donation_Channel] as [insertedDonation_Channel], 
      inserted.[Source_Channel] as [insertedSource_Channel], 
      inserted.[Recruitment_Source] as [insertedRecruitment_Source], 
      inserted.[Merch_ProductID] as [insertedMerch_ProductID], 

      updated.[Constituent_ID] as [updatedConstituent_ID], 
      updated.[RE_Gift_ID] as [updatedRE_Gift_ID], 
      updated.[Gift_ID] as [updatedGift_ID], 
      updated.[Gift_Date_Added] as [updatedGift_Date_Added], 
      updated.[Gift_Date] as [updatedGift_Date], 
      updated.[Name] as [updatedName], 
      updated.[Gift_Type] as [updatedGift_Type], 
      updated.[Gift_Amount] as [updatedGift_Amount], 
      updated.[Frequency] as [updatedFrequency], 
      updated.[Pay_Method] as [updatedPay_Method], 
      updated.[Appeal] as [updatedAppeal], 
      updated.[Campaign] as [updatedCampaign], 
      updated.[Gift Added By] as [updatedGift Added By], 
      updated.[Gift Reference] as [updatedGift Reference], 
      updated.[SoftCredit] as [updatedSoftCredit], 
      updated.[Relationship Manager] as [updatedRelationship Manager], 
      updated.[CostCentre] as [updatedCostCentre], 
      updated.[Recruiter] as [updatedRecruiter], 
      updated.[Sitecode] as [updatedSitecode], 
      updated.[Zerodebit] as [updatedZerodebit], 
      updated.[Donation_Channel] as [updatedDonation_Channel], 
      updated.[Source_Channel] as [updatedSource_Channel], 
      updated.[Recruitment_Source] as [updatedRecruitment_Source], 
      updated.[Merch_ProductID] as [updatedMerch_ProductID]; 



    SELECT @@ROWCOUNT; 
    GO 

dies wirft einen Fehler:

Msg 5334, Level 16, State 2, Line 86
The identifier 'target.gift_date' cannot be bound. Only target columns and columns in the clause scope are allowed in the 'WHEN NOT MATCHED BY SOURCE' clause of a MERGE statement.

Antwort

2

Hier ist ein Full-Skript, das zeigt, wie ich es tun würde. Checked in SQL Server 2008.

Beispieldaten

DECLARE @TDst TABLE (ID int, dt date, DataValue int); 
DECLARE @TSrc TABLE (ID int, dt date, DataValue int); 

INSERT INTO @TDst (ID, dt, DataValue) VALUES 
(11, '2015-01-01', 1100) -- don't delete 
,(12, '2015-02-02', 1200) -- don't delete 
,(21, '2016-01-01', 2100) -- this should be deleted 
,(22, '2016-02-02', 2200) -- this would remain as is 
,(23, '2016-03-03', 2300) -- this would be updated 
; 

INSERT INTO @TSrc (ID, dt, DataValue) VALUES 
(22, '2016-02-02', 2200) -- same date and value, don't update 
,(23, '2016-03-03', 2388) -- update 
,(24, '2016-04-04', 2488) -- add 
; 

SELECT * FROM @TDst; 

+----+------------+-----------+ 
| ID |  dt  | DataValue | 
+----+------------+-----------+ 
| 11 | 2015-01-01 |  1100 | 
| 12 | 2015-02-02 |  1200 | 
| 21 | 2016-01-01 |  2100 | 
| 22 | 2016-02-02 |  2200 | 
| 23 | 2016-03-03 |  2300 | 
+----+------------+-----------+ 

Abfrage

MERGE INTO @TDst AS Dst 
USING @TSrc as Src 
ON (Dst.ID = Src.ID) 

--When rows are matched, update the records if there is any change 
WHEN MATCHED 
    AND (Dst.dt <> Src.dt 
    OR Dst.DataValue <> Src.DataValue) 
THEN 
UPDATE 
SET 
    Dst.dt = Src.dt 
    ,Dst.DataValue = Src.DataValue 

-- when no records are matched then insert from source into target. 
WHEN NOT MATCHED BY TARGET THEN 
INSERT (ID, dt, DataValue) 
VALUES (Src.ID, Src.dt, Src.DataValue) 

-- When there is a row that exists in target table and 
-- same record does not exist in source table then delete this record from target table 
WHEN NOT MATCHED BY SOURCE AND Dst.dt >= '2016-01-01' THEN 
DELETE 
; 

SELECT * FROM @TDst; 

Ergebnis

+----+------------+-----------+ 
| ID |  dt  | DataValue | 
+----+------------+-----------+ 
| 11 | 2015-01-01 |  1100 | 
| 12 | 2015-02-02 |  1200 | 
| 22 | 2016-02-02 |  2200 | 
| 23 | 2016-03-03 |  2388 | 
| 24 | 2016-04-04 |  2488 | 
+----+------------+-----------+ 

Wie Sie sehen können, wurden die Daten vor 2016 beibehalten, aber Daten im Jahr 2016 wurden ersetzt.

Wenn Ihre Source Tabelle nur Daten von 2016 hat, dann müssen Sie >= '2016-01-01' zusätzliche Filter hinzufügen nur auf die WHEN NOT MATCHED BY SOURCE Klausel zu verhindern Reihen vor 2016.


Löschen

Der Fehler, den Sie bekommen am meisten wahrscheinlich verursacht durch den folgenden zusätzlichen Filter, der nicht benötigt wird:

WHEN NOT MATCHED BY TARGET and year(target.gift_date) >= '2016' 
+0

Dank Vladimir, das half. Stellt sich heraus, dass die letzte Zeile, die Sie identifiziert haben, das Problem war, als ich Target aufgelistet habe, wo es eine Quelle hätte sein sollen. – Maz

Verwandte Themen