Ich habe eine Tabelle, die derzeit doppelte Werte in einer Spalte enthält.
Ich kann diese fehlerhaften Duplikate nicht entfernen, möchte jedoch verhindern, dass zusätzliche nicht eindeutige Werte hinzugefügt werden.
Kann ich eine erstellen UNIQUE
, die nicht auf vorhandene Konformität überprüft?
Ich habe versucht, NOCHECK
aber war erfolglos.
In diesem Fall habe ich eine Tabelle, die Lizenzinformationen mit "CompanyName" verknüpft.
BEARBEITEN: Mehrere Zeilen mit demselben "CompanyName" sind fehlerhafte Daten, aber wir können diese Duplikate derzeit nicht entfernen oder aktualisieren. Ein Ansatz besteht darin, die INSERT
s eine gespeicherte Prozedur verwenden zu lassen, die bei Duplikaten fehlschlägt. Wenn SQL die Eindeutigkeit selbst überprüfen könnte, wäre dies vorzuziehen.
Diese Daten werden nach Firmennamen abgefragt. Für die wenigen vorhandenen Duplikate bedeutet dies, dass mehrere Zeilen zurückgegeben und angezeigt werden. Dies ist zwar falsch, in unserem Anwendungsfall jedoch akzeptabel. Ziel ist es, dies in Zukunft zu verhindern. Aus den Kommentaren geht hervor, dass ich diese Logik in den gespeicherten Prozeduren ausführen muss.
Antworten:
Die Antwort ist ja". Sie können dies mit einem gefilterten Index tun (siehe hier für Dokumentation).
Zum Beispiel können Sie Folgendes tun:
Dadurch wird ein eindeutiger Index nur für neue Zeilen und nicht für die alten Zeilen erstellt. Diese spezielle Formulierung würde Duplikate mit vorhandenen Werten ermöglichen.
Wenn Sie nur eine Handvoll Duplikate haben, können Sie Folgendes tun:
quelle
Ja, das kannst du.
Hier ist eine Tabelle mit Duplikaten:
Lassen Sie uns vorhandene ignorieren und sicherstellen, dass keine neuen Duplikate hinzugefügt werden können:
Lassen Sie uns diese Lösung testen:
quelle
UNIQUE
Einschränkung in einer nullwertfähigen Spalte sicher, dass höchstens ein einzigerNULL
Wert vorhanden ist. Der SQL-Standard (und fast alle anderen SQL-DBMS) gibt an, dass eine beliebige Anzahl vonNULL
Werten zulässig sein soll (dh, die Einschränkung sollte Nullwerte ignorieren).Der gefilterte eindeutige Index ist eine brillante Idee, hat aber einen kleinen Nachteil - egal ob Sie die
WHERE identity_column > <current value>
Bedingung oder die verwendenWHERE identity_column NOT IN (<list of ids for duplicate values here>)
.Mit dem ersten Ansatz können Sie auch in Zukunft doppelte Daten einfügen, Duplikate vorhandener (jetzt) Daten. Wenn Sie beispielsweise jetzt (auch nur eine) Zeile mit haben
CompanyName = 'Software Inc.'
, wird der Index das Einfügen einer weiteren Zeile mit demselben Firmennamen nicht verbieten. Es wird es nur verbieten, wenn Sie es zweimal versuchen.Mit dem zweiten Ansatz gibt es eine Verbesserung, die oben genannten werden nicht funktionieren (was gut ist). Sie werden jedoch weiterhin in der Lage sein, mehr Duplikate oder vorhandene Duplikate einzufügen. Wenn Sie beispielsweise jetzt (zwei oder mehr) Zeilen mit haben
CompanyName = 'DoubleData Co.'
, verbietet der Index das Einfügen einer weiteren Zeile mit demselben Firmennamen nicht. Es wird es nur verbieten, wenn Sie es zweimal versuchen.(Update) Dies kann korrigiert werden, wenn Sie für jeden doppelten Namen eine ID aus der Ausschlussliste streichen. Wenn wie im obigen Beispiel vier Zeilen mit Duplikaten
CompanyName = DoubleData Co.
und IDs vorhanden sind4,6,8,9
, sollte die Ausschlussliste nur drei dieser IDs enthalten.Beim zweiten Ansatz ist ein weiterer Nachteil die umständliche Bedingung (wie umständlich es ist, wie viele Duplikate überhaupt vorhanden sind), da SQL-Server den
NOT IN
Operator imWHERE
Teil der gefilterten Indizes nicht zu unterstützen scheint . Siehe SQL-Fiddle . StattdessenWHERE (CompanyID NOT IN (3,7,4,6,8,9))
müssen Sie so etwas haben, dassWHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
ich nicht sicher bin, ob es bei einer solchen Bedingung Auswirkungen auf die Effizienz gibt, wenn Sie Hunderte von doppelten Namen haben.Eine andere Lösung (ähnlich wie bei @Alex Kuznetsov) besteht darin, eine weitere Spalte hinzuzufügen, diese mit Rangnummern zu füllen und einen eindeutigen Index mit der folgenden Spalte hinzuzufügen:
Das Einfügen einer Zeile mit doppeltem Namen schlägt aufgrund der
DEFAULT 1
Eigenschaft und des eindeutigen Index fehl . Dies ist immer noch nicht 100% narrensicher (während es Alex ist). Duplikate werden weiterhin eingefügt, wenn dasRn
explizit in derINSERT
Anweisung festgelegt ist oder wenn dieRn
Werte in böswilliger Absicht aktualisiert werden.SQL-Fiddle-2
quelle
Eine andere Alternative besteht darin, eine Skalarfunktion zu schreiben, die prüft, ob in der Tabelle bereits ein Wert vorhanden ist, und diese Funktion dann über eine Prüfbedingung aufzurufen.
Dies wird schreckliche Dinge für die Leistung tun.
quelle
Ich suche nach dem gleichen - erstelle einen nicht vertrauenswürdigen eindeutigen Index, damit vorhandene fehlerhafte Daten ignoriert werden, aber neue Datensätze können keine Duplikate von allem sein, was bereits vorhanden ist.
Beim Lesen dieses Threads denke ich, dass eine bessere Lösung darin besteht, einen Trigger zu schreiben, der die übergeordnete Tabelle auf Duplikate überprüft und ROLLBACK TRAN, wenn zwischen diesen Tabellen Duplikate vorhanden sind.
quelle