L'index unique filtré est une idée brillante, mais il présente un inconvénient mineur - que vous utilisiez la WHERE identity_column > <current value>
condition ou le WHERE identity_column NOT IN (<list of ids for duplicate values here>)
.
Avec la première approche, vous pourrez toujours insérer des données en double dans le futur, des copies de données existantes (à présent). Par exemple, si vous avez (même une seule) ligne avec CompanyName = 'Software Inc.'
, l'index n'interdit pas l'insertion d'une ligne supplémentaire avec le même nom de société. Cela ne l'interdira que si vous essayez deux fois.
Avec la deuxième approche, il y a une amélioration, ce qui précède ne fonctionnera pas (ce qui est bon.) Cependant, vous pourrez toujours insérer plus de doublons ou des doublons existants. Par exemple, si vous avez (deux ou plus) lignes maintenant avecCompanyName = 'DoubleData Co.'
, l'index n'interdit pas l'insertion d'une ligne supplémentaire avec le même nom de société. Cela ne l'interdira que si vous essayez deux fois.
(Mise à jour) Cela peut être corrigé si, pour chaque nom en double, vous gardez un identifiant sur la liste d'exclusion. Si, comme dans l'exemple ci-dessus, il y a 4 lignes avec doublons CompanyName = DoubleData Co.
et identifiants 4,6,8,9
, la liste d'exclusion ne devrait contenir que 3 de ces identifiants.
Avec la seconde approche, un autre inconvénient est la lourdeur (son importance dépend du nombre de doublons existant en premier lieu), car SQL-Server ne semble pas prendre en charge l' NOT IN
opérateur dans la WHERE
partie des index filtrés. Voir SQL-Fiddle . Au lieu de WHERE (CompanyID NOT IN (3,7,4,6,8,9))
, vous devrez avoir quelque chose commeWHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
je ne suis pas sûr que cette condition ait des conséquences sur l'efficacité, si vous avez des centaines de noms en double.
Une autre solution (similaire à celle de @Alex Kuznetsov) consiste à ajouter une autre colonne, à la renseigner avec des numéros de rang et à ajouter un index unique comprenant cette colonne:
ALTER TABLE Company
ADD Rn TINYINT DEFAULT 1;
UPDATE x
SET Rn = Rnk
FROM
( SELECT
CompanyID,
Rn,
Rnk = ROW_NUMBER() OVER (PARTITION BY CompanyName
ORDER BY CompanyID)
FROM Company
) x ;
CREATE UNIQUE INDEX CompanyName_UQ
ON Company (CompanyName, Rn) ;
Ensuite, l'insertion d'une ligne avec un nom en double échouera à cause de la DEFAULT 1
propriété et de l'index unique. Ce n'est toujours pas à 100% infaillible (alors qu'Alex l'est). Les doublons resteront quand même insérés si le Rn
est explicitement défini dans l' INSERT
instruction ou si les Rn
valeurs sont mises à jour de manière malveillante.
SQL-Fiddle-2