SQL Server слияние и нарушение ПК - PullRequest
0 голосов
/ 28 ноября 2018

Я пытаюсь понять, почему в сценарии, подобном следующему

DECLARE @source TABLE 
             (
                 orderId NVARCHAR(50),
                 customerId NVARCHAR(50)
             )

DECLARE @target TABLE 
             (
                  orderId NVARCHAR(50) PRIMARY KEY,
                  customerId NVARCHAR(50) NOT NULL
             )

INSERT INTO @source 
VALUES ('test', '123'), ('test', '234')

MERGE @target AS TRG
USING (SELECT DISTINCT orderId, customerId
       FROM @source) AS SRC ON SRC.orderId = TRG.orderId

WHEN MATCHED THEN
    UPDATE SET TRG.customerId = SRC.customerId

WHEN NOT MATCHED BY TARGET THEN
    INSERT (orderId, customerId)
    VALUES (orderId, customerId);

, я получаю ошибку нарушения дублирующего ключа:

Сообщение 2627, уровень 14,Состояние 1, строка 21
Нарушение ограничения PRIMARY KEY 'PK __ # B3D7759__0809335D4BE1521F'.Невозможно вставить дубликат ключа в объект 'dbo. @ Target'.Дублирующим значением ключа является (test).

Я ожидаю, что оператор update найдет существующий ключ и обновит customerId, чтобы в конце я попал в строку @target 1 с orderId = 'test 'and customerId =' 234 '.

Насколько я могу предположить, вместо этого он пытается вставить все записи, так как сначала не находит совпадения клавиш в начале слияния, вызывая нарушение какИсточник содержит ключ несколько раз.

Это правильно?Есть ли способ достичь того, что я ожидаю, используя функцию слияния?


@ user1443098

Я прочитал вашу ссылку, Спасибо.Однако у меня есть массивная вставка данных, исходящих из исходной таблицы и входящих в 10 разных таблиц;Я попытался реализовать процедуру с курсором, и это заняло около 0,5 с на запись (со всеми операторами if Существуют).С помощью оператора слияния 300 строк были вставлены в 10 различных таблиц менее чем за одну секунду.Так что в моем случае это сильно влияет на производительность.

1 Ответ

0 голосов
/ 28 ноября 2018

В @source есть две записи с одинаковым OrderID.Не найдено ни одной записи в @target, поэтому предложение NOT MATCHED пытается вставить обе эти записи.Но он не может этого сделать, потому что первичный ключ на OrderID в таблице @target требует, чтобы все вставленные записи имели уникальные значения для OrderID.Дублирование значений в первичный ключ вызывает нарушение первичного ключа.

Если вы ожидаете, что в источнике возможны дубликаты ... вы должны устранить их в своем подзапросе USING.Как то так:

(SELECT orderId, max(customerId) customerId
FROM @source
group by orderId)
...