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 verwenden WHERE 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 sind 4,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 im WHERE
Teil der gefilterten Indizes nicht zu unterstützen scheint . Siehe SQL-Fiddle . Stattdessen WHERE (CompanyID NOT IN (3,7,4,6,8,9))
müssen Sie so etwas haben, dass WHERE (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:
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) ;
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 das Rn
explizit in der INSERT
Anweisung festgelegt ist oder wenn die Rn
Werte in böswilliger Absicht aktualisiert werden.
SQL-Fiddle-2