Beaucoup de gens vous proposeront de l'utiliser MERGE
, mais je vous déconseille. Par défaut, il ne vous protège pas plus de la concurrence et des conditions de concurrence que de multiples déclarations, et il présente d'autres dangers:
http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/
Même avec cette syntaxe "plus simple" disponible, je préfère toujours cette approche (gestion des erreurs omise pour plus de brièveté):
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;
Beaucoup de gens vont suggérer de cette façon:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
INSERT ...
END
COMMIT TRANSACTION;
Mais tout cela permet de s'assurer que vous devrez peut-être lire le tableau deux fois pour localiser la ou les lignes à mettre à jour. Dans le premier exemple, vous n'aurez besoin de localiser les lignes qu'une seule fois. (Dans les deux cas, si aucune ligne n'est trouvée lors de la lecture initiale, une insertion se produit.)
D'autres proposeront de cette façon:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
Cependant, cela est problématique si, pour aucune autre raison que de laisser SQL Server intercepter les exceptions que vous auriez pu empêcher en premier lieu, c'est beaucoup plus cher, sauf dans le rare scénario où presque chaque insertion échoue. J'en prouve autant ici: