在Oracle 11g中合并时,我要删除与源不匹配的目标行

问题描述

sql> SELECT * FROM SOURCE;

 MEMBER_ID FirsT_NAME LAST_NAME  RANK
---------- ---------- ---------- --------------------
         1 Abel       Wolf       Gold
         2 Clarita    Franco     Platinum
         3 Darryl     Giles      Silver
         4 Dorthea    Suarez     Silver
         5 Katrina    Wheeler    Silver
         6 Lilian     Garza      Silver
         7 Ossie      Summers    Gold
         8 Paige      Mcfarland  Platinum
         9 Ronna      Britt      Platinum
        10 Tressie    Short      bronze

10 rows selected.

sql> SELECT * FROM DESTINATION;

 MEMBER_ID FirsT_NAME LAST_NAME  RANK
---------- ---------- ---------- --------------------
         1 Abel       Wolf       Silver
         2 Clarita    Franco     Platinum
         3 Darryl     Giles      bronze
         4 Dorthea    Gate       Gold
         5 Katrina    Wheeler    Silver
         6 Lilian     Stark      Silver
        11 Chris      Well       Silver

7 rows selected.

当我尝试执行以下查询时,它正在执行,但未从目标表中删除记录11:

MERGE INTO DESTINATION D
USING SOURCE S
ON (D.MEMBER_ID = S.MEMBER_ID)
WHEN MATCHED THEN
  UPDATE
     SET D.FirsT_NAME = S.FirsT_NAME,D.LAST_NAME  = S.LAST_NAME,D.RANK       = S.RANK 
  DELETE
   WHERE D.MEMBER_ID <> S.MEMBER_ID
WHEN NOT MATCHED THEN
  INSERT
    (D.MEMBER_ID,D.FirsT_NAME,D.LAST_NAME,D.RANK)
  VALUES
    (S.MEMBER_ID,S.FirsT_NAME,S.LAST_NAME,S.RANK);

解决方法

因为当前逻辑隐式使用INNER JOIN,并且表MEMBER_ID = 11中不存在SOURCE,所以该值不会引起MATCHED的情况,因此永远不会已被删除。

您可以如下使用OUTER JOIN之类的FULL JOIN

MERGE INTO DESTINATION D
USING (SELECT NVL(S.MEMBER_ID,D.MEMBER_ID) AS MEMBER_ID,S.FIRST_NAME,S.LAST_NAME,S.RANK 
         FROM DESTINATION D
         FULL JOIN SOURCE S
           ON S.MEMBER_ID = D.MEMBER_ID) S
   ON (NVL(S.MEMBER_ID,D.MEMBER_ID) = D.MEMBER_ID)
WHEN MATCHED THEN
  UPDATE
     SET D.FIRST_NAME = S.FIRST_NAME,D.LAST_NAME  = S.LAST_NAME,D.RANK       = S.RANK 
  DELETE
   WHERE S.FIRST_NAME IS NULL
  WHEN NOT MATCHED THEN
  INSERT
    (D.MEMBER_ID,D.FIRST_NAME,D.LAST_NAME,D.RANK)
  VALUES
    (S.MEMBER_ID,S.RANK);

Demo