Слияние SQL не удается вставить, а затем обновить две идентичные строки из целевой таблицы

Я пытаюсь объединить две таблицы с помощью SQL Merge в следующем скрипте:

 BEGIN TRAN;
DECLARE @T TABLE(Id BigInt);
MERGE Target AS T
USING Source AS S
ON (T.ObjectName = S.ObjectName) 
WHEN NOT MATCHED BY TARGET 
     THEN INSERT(ObjectName,Value,[TimeStamp],Quality) VALUES(S.ObjectName, S.Value,S.[TimeStamp],S.Quality)
WHEN MATCHED 
    THEN UPDATE SET 
    T.Value = S.Value,
    T.Quality=S.Quality

OUTPUT S.Id INTO @T;
DELETE Source
WHERE Id in (SELECT Id
                     FROM @T);
if @@Error > 0
Rollback
else
COMMIT Tran
GO 

Я пытаюсь вставить новые записи с "Target" на "Source", и записи "Matched" будут обновлены в "Source" таблице. Проблема, с которой я сталкиваюсь, заключается в том, что иногда в исходной таблице есть два одинаковых "Not Matched Rows". В соответствии с логикой скрипта и моим требованием он должен вставить первый "Not Matched", тогда второй «Not Matched» нужно будет рассматривать как обновление, а не как вставку, поскольку теперь это строка "Matched", потому что мы уже вставил первую запись.

Кажется, что мое слияние работает как один массовый скрипт, где первая вставка не замечается, когда скрипт достигает второй идентичной строки. Так работает «SQL Merge» или это мой скрипт?

Спасибо


person Hassan Mokdad    schedule 18.07.2013    source источник


Ответы (1)


Предполагая, что строка с более поздней меткой времени должна "выиграть", почему бы не удалить дубликат как часть вашего SOURCE запроса:

;With Selection as (
    select ObjectName,Value,Quality,
      ROW_NUMBER() OVER (PARTITION BY ObjectName ORDER BY Timestamp desc) as rn,
      MIN(Timestamp) OVER (PARTITION BY ObjectName) as Timestamp
    from
      Source
)
MERGE Target AS T
USING (select * from Selection where rn=1) AS S
--The rest is unaltered
...

И в этом нет ничего необычного в MERGE - все операторы DML действуют «так, как будто» все строки обрабатываются одновременно.

person Damien_The_Unbeliever    schedule 18.07.2013
comment
Спасибо за ответ, я попробую прямо сейчас и вернусь к вам - person Hassan Mokdad; 18.07.2013
comment
Я бы не стал спрашивать, почему бы и нет, я бы сказал, что это нужно делать именно так. @HassanMokdad Вы всегда должны фильтровать свой источник перед оператором слияния. Если в источнике есть повторяющиеся строки, которые не соответствуют обеим, будут вставлены (что может вызвать ошибку PK в цели) - sqlfiddle.com / #! 6 / d9257 / 6 Если дубликаты уже существуют в целевом объекте, MERGE завершается ошибкой (невозможно обновить одну и ту же строку дважды) - sqlfiddle.com / #! 6 / 81f90 / 1 - person Nenad Zivkovic; 18.07.2013
comment
@Nendad, вы правы, я столкнулся с ошибкой ПК. а в других случаях я получал ошибку «Невозможно обновить одну и ту же строку дважды». Теперь я лучше понял SQL Merge, спасибо - person Hassan Mokdad; 18.07.2013
comment
Спасибо, Дэмиен, сработало отлично - person Hassan Mokdad; 18.07.2013