Lorsqu'il s'agit de garantir l'unicité d'enregistrements sur une condition qui ne peut être exprimée par une contrainte UNIQUE ou PRIMARY KEY, il faut en effet s'assurer que la vérification d'existence et l'insertion se font en une seule transaction. Vous pouvez y parvenir soit :
- Utiliser une instruction SQL pour effectuer la vérification et l'insertion (votre troisième option)
- Utiliser une transaction avec le niveau d'isolement approprié
Il existe cependant une quatrième méthode qui vous aidera à mieux structurer votre code et à le faire fonctionner dans des situations où vous devez traiter un lot d'enregistrements à la fois. Vous pouvez créer une variable TABLE ou une table temporaire, insérer tous les enregistrements qui doivent y être insérés, puis écrire les instructions INSERT, UPDATE et DELETE en fonction de cette variable.
Vous trouverez ci-dessous le (pseudo)code illustrant cette approche :
-- Logic to create the data to be inserted if necessary
DECLARE @toInsert TABLE (idCol INT PRIMARY KEY,dataCol VARCHAR(MAX))
INSERT INTO @toInsert (idCol,dataCol) VALUES (1,'row 1'),(2,'row 2'),(3,'row 3')
-- Logic to insert the data
INSERT INTO realTable (idCol,dataCol)
SELECT TI.*
FROM @toInsert TI
WHERE NOT EXISTS (SELECT 1 FROM realTable RT WHERE RT.dataCol=TI.dataCol)
Dans de nombreuses situations, j'utilise cette approche car elle rend le code TSQL plus facile à lire, il est possible de le refactoriser et d'y appliquer des tests unitaires.