SQL Server MERGE с двумя результатами сопоставления - PullRequest
0 голосов
/ 13 июня 2018

Я пытаюсь создать архив (TGT), который содержит последнюю версию скользящей (SRC) таблицы.SRC может содержать несколько версий и дубликатов, но TGT должен содержать только уникальные, самые последние строки.

Есть 4 столбца - A, B, C и D, которые образуют уникальный ключ, и 5-й столбец, 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 => SRC старше или равно, поэтому ничего не следует делать

  3. Нет соответствия => строка SRC должна быть вставлена ​​в TGT

Проблема, с которой я сталкиваюсь, связана с результатами 2 и 3, поскольку MERGE допускает только два предложения WHEN MATCHED, и вв этом случае один должен быть UPDATE, а другой - DELETE.Я действительно хочу UPDATE и "ничего не делать"

Что-то вроде этого:

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, но затем выдается предупреждение о дублировании ключа, потому что он пытается вставить более старую запись

I 'использую SQL Server 2016, если это что-то меняет

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Не уверен, будет ли уместным ответить на мой собственный вопрос, но я нашел решение, которое , кажется, работает (пожалуйста, исправьте меня, если вы видите проблему с этим!) И подумал, что поделюсь им на будущеепосетители:

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)
0 голосов
/ 13 июня 2018

Вы можете манипулировать исходной таблицей столько, сколько хотите, с помощью 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.

Вы также можете использовать ROW_NUMBER(), если вам нужно более 1 столбца для определения самой последней версии (придется фильтровать, где номер строки = 1).

...