J'ai une table qui a actuellement des valeurs en double dans une colonne.
Je ne peux pas supprimer ces doublons erronés, mais j'aimerais empêcher l'ajout de valeurs non uniques supplémentaires.
Puis-je créer un UNIQUE
qui ne vérifie pas la conformité existante?
J'ai essayé d'utiliser NOCHECK
mais j'ai échoué.
Dans ce cas, j'ai un tableau qui lie les informations de licence à "CompanyName"
EDIT: avoir plusieurs lignes avec le même "CompanyName" est une mauvaise donnée, mais nous ne pouvons pas supprimer ou mettre à jour ces doublons pour le moment. Une approche consiste à INSERT
utiliser une procédure stockée qui échouera pour les doublons ... S'il était possible que SQL vérifie lui-même l'unicité, ce serait préférable.
Ces données sont interrogées par nom de société. Pour les quelques doublons existants, cela signifie que plusieurs lignes sont renvoyées et affichées ... Bien que cela ne soit pas correct, cela est acceptable dans notre cas d'utilisation. Le but est de le prévenir à l'avenir. Il me semble d'après les commentaires que je dois faire cette logique dans les procédures stockées.
Réponses:
La réponse est oui". Vous pouvez le faire avec un index filtré (voir ici pour la documentation).
Par exemple, vous pouvez faire:
Cela crée un index unique, uniquement sur les nouvelles lignes, plutôt que sur les anciennes. Cette formulation particulière permettrait des doublons avec les valeurs existantes.
Si vous n'avez qu'une poignée de doublons, vous pouvez faire quelque chose comme:
la source
Oui, tu peux faire ça.
Voici un tableau avec des doublons:
Ignorons ceux qui existent déjà et assurons-nous qu'aucun nouveau duplicata ne puisse être ajouté:
Laissez-nous tester cette solution:
la source
UNIQUE
contrainte dans une colonne nullable garantit qu'il existe au plus uneNULL
valeur unique . Le standard SQL (et presque tous les autres SGBD SQL) indique qu'il doit autoriser un nombre quelconque deNULL
valeurs (c'est-à-dire que la contrainte doit ignorer les valeurs nulles).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 leWHERE 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 avec
CompanyName = '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 identifiants4,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 laWHERE
partie des index filtrés. Voir SQL-Fiddle . Au lieu deWHERE (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:
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 leRn
est explicitement défini dans l'INSERT
instruction ou si lesRn
valeurs sont mises à jour de manière malveillante.SQL-Fiddle-2
la source
Une autre alternative consiste à écrire une fonction scalaire qui vérifie si une valeur existe déjà dans la table, puis à appeler cette fonction à partir d'une contrainte de vérification.
Cela fera des choses horribles à la performance.
la source
Je cherche la même chose - créer un index unique non fiable pour que les mauvaises données existantes soient ignorées, mais les nouveaux enregistrements ne peuvent pas être des doublons de tout ce qui existe déjà.
En lisant ce fil de discussion, il me semble qu’une meilleure solution consiste à écrire un déclencheur qui vérifie la présence de doublons dans la table parent [inséré] et, s’il existe des doublons, ROLLBACK TRAN.
la source