Много хора ще ви предложат да използвате MERGE
, но ви предупреждавам срещу това. По подразбиране той не ви защитава от паралелност и условия на състезание повече от множество изявления, но въвежда други опасности:
- Внимавайте с изявлението MERGE на SQL Server
- Какво да избягвате, ако искате да използвате MERGE
- SQL Server UPSERT шаблони и антимодели
Дори с наличен този "по-прост" синтаксис, аз все още предпочитам този подход (обработката на грешки е пропусната за краткост):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;
Повече информация за този UPSERT
подход тук:
- Моля, спрете да използвате този анти-модел на UPSERT
Много хора ще предложат този начин:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
BEGIN
INSERT ...
END
COMMIT TRANSACTION;
Но всичко това постига гарантира, че може да се наложи да прочетете таблицата два пъти, за да намерите редовете, които трябва да бъдат актуализирани. В първата извадка ще трябва да намерите редовете само веднъж. (И в двата случая, ако не бъдат намерени редове от първоначалното четене, се получава вмъкване.)
Други ще предложат този начин:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
Това обаче е проблематично, ако не по друга причина, освен да позволите на SQL Server да улавя изключения, които бихте могли да предотвратите на първо място, е много по-скъпо, освен в редкия сценарий, при който почти всяко вмъкване се проваля. Доказвам толкова много тук:
- Проверка за потенциални нарушения на ограниченията, преди да влезете в TRY/CATCH
- Влияние върху производителността на различни техники за обработка на грешки
Не сте сигурни какво мислите, че печелите, като имате едно изявление; Не мисля, че печелиш нищо. MERGE
е едно изявление, но така или иначе трябва наистина да изпълнява множество операции - въпреки че ви кара да мислите, че не го прави.