SQL Server MERGE具有两个匹配结果

时间:2018-06-13 13:28:45

标签: sql sql-server sql-server-2016

我正在尝试创建一个包含最新版滚动(SRC)表的存档(TGT)。 SRC可能包含多个版本和重复项,但TGT应仅包含唯一的最新行。

有4列 - A,B,C和D形成一个UNIQUE键,第五列E代表一个版本号。

所以如果我加入以下内容:

SRC.A = TGT.A AND SRC.B = TGT.B AND SRC.C = TGT.C AND SRC.D = TGT.D

应该有两个结果 - 匹配或不匹配。但是,如果有匹配,我有一个我想申请的子条件,所以我真正想要找到3个可能的结果:

  1. 匹配AND SRC.E > TGT.E => SRC是更高版本,因此TGT行应该更新

  2. 匹配AND SRC.E <= TGT.E =&gt; SRC较旧或相同,因此不应该做任何事情

  3. 不匹配=&gt;应将SRC行插入TGT

  4. 我遇到的问题是结果2和3,因为MERGE只允许两个WHEN MATCHED子句,在这种情况下,一个必须是UPDATE而另一个必须是一个DELETE。我真的想要一个UPDATE和一个&#34;什么都不做&#34;

    这些方面的东西:

    MERGE
        Target AS TGT
    USING
        Source AS SRC ON SRC.A = TGT.A AND SRC.B = TGT.B AND SRC.C = TGT.C AND SRC.D = TGT.D
    
    WHEN MATCHED AND SRC.E > TGT.E   -- SRC is newer, so update TGT
        THEN UPDATE SET TGT.E = SRC.E
    
    WHEN MATCHED  -- "AND SRC.E <= TGT.E” is implied...
        -- SRC is older or equal, so do nothing
    
    WHEN NOT MATCHED BY TARGET   -- SRC doesn't exist in TGT, so insert it
        THEN INSERT VALUES (SRC.A, SRC.B, SRC.C, SRC.D, SRC.E)
    
    这可能吗?它是否像重新安排我的加入一样简单?

    我尝试删除第二个WHEN MATCHED子句,但之后会导致重复键警告,因为它会尝试插入旧记录

    我使用SQL Server 2016,如果它改变了什么

2 个答案:

答案 0 :(得分:0)

您可以使用CTE或子查询操作源表,如下例所示。

;WITH MostRecentSourceVersion AS
(
    SELECT
        S.A,
        S.B,
        S.C,
        S.D,
        E = MAX(S.E) -- Assuming the most recent is the MAX
    FROM
        Source AS S
    GROUP BY
        S.A, -- Your keys here
        S.B,
        S.C,
        S.D
)
MERGE
    Target AS TGT
USING
    MostRecentSourceVersion AS SRC
ON
    SRC.A=TGT.A AND SRC.B=TGT.B AND SRC.C=TGT.C AND SRC.D=TGT.D
WHEN MATCHED AND SRC.E > TGT.E   -- SRC is newer, so update TGT
    THEN UPDATE SET TGT.E = SRC.E
WHEN NOT MATCHED BY TARGET   -- SRC doesn't exist in TGT, so insert it
    THEN INSERT VALUES (SRC.A, SRC.B, SRC.C, SRC.D, SRC.E);

通过这种方式,您可以确定,如果匹配,则始终为1。

如果您需要多于1列来确定最新版本(必须在行号= 1的位置进行过滤),您也可以使用ROW_NUMBER()

答案 1 :(得分:0)

不确定是否适合回答我自己的问题,但我找到了似乎的解决方案(如果您发现问题,请纠正我!)并认为我将分享给未来的访客:

MERGE
    Target AS TGT
USING
    (
         SELECT TOP 1 WITH TIES
             A, B, C, D
         FROM
             Source
         ORDER BY
             ROW_NUMBER() OVER (PARTITION BY A, B, C, D ORDER BY E DESC)
     ) AS SRC
ON
    SRC.A = TGT.A
    AND SRC.B = TGT.B
    AND SRC.C = TGT.C
    AND SRC.D = TGT.D
WHEN MATCHED AND SRC.E > TGT.E
    THEN UPDATE SET TGT.E = SRC.E
WHEN NOT MATCHED BY TARGET
    THEN INSERT VALUES (SRC.A, SRC.B, SRC.C, SRC.D, SRC.E)