L'indice univoco filtrato è un'idea geniale ma presenta uno svantaggio minore, indipendentemente dal fatto che si utilizzi la WHERE identity_column > <current value>
condizione o il WHERE identity_column NOT IN (<list of ids for duplicate values here>)
.
Con il primo approccio, sarai ancora in grado di inserire dati duplicati in futuro, duplicati di dati esistenti (ora). Ad esempio, se ora hai (anche solo una) riga con CompanyName = 'Software Inc.'
, l'indice non proibirà l'inserimento di un'altra riga con lo stesso nome di società. Lo proibirà solo se ci provi due volte.
Con il secondo approccio c'è un miglioramento, quanto sopra non funzionerà (il che è buono.) Tuttavia, sarai comunque in grado di inserire più duplicati o duplicati esistenti. Ad esempio, se ora disponi di (due o più) righe con CompanyName = 'DoubleData Co.'
, l'indice non proibirà l'inserimento di un'altra riga con lo stesso nome di società. Lo proibirà solo se ci provi due volte.
(Aggiorna) Questo può essere corretto se per ogni nome duplicato, si tiene fuori dalla lista di esclusione un ID. Se, come nell'esempio precedente, ci sono 4 righe con duplicati CompanyName = DoubleData Co.
e ID 4,6,8,9
, l'elenco di esclusione dovrebbe avere solo 3 di questi ID.
Con il secondo approccio un altro svantaggio è la condizione ingombrante (quanto ingombrante dipende da quanti duplicati ci sono in primo luogo), dal momento che SQL Server sembra non supportare l' NOT IN
operatore nella WHERE
parte degli indici filtrati. Vedi SQL-Fiddle . Invece WHERE (CompanyID NOT IN (3,7,4,6,8,9))
, dovresti avere qualcosa di simile, WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
non sono sicuro che ci siano implicazioni di efficienza con tale condizione, se hai centinaia di nomi duplicati.
Un'altra soluzione (simile a quella di @Alex Kuznetsov) è quella di aggiungere un'altra colonna, compilarla con i numeri di rango e aggiungere un indice univoco che includa questa colonna:
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) ;
Quindi, l'inserimento di una riga con un nome duplicato non riuscirà a causa della DEFAULT 1
proprietà e dell'indice univoco. Questo non è ancora sicuro al 100% (mentre quello di Alex lo è). I duplicati continueranno comunque a Rn
essere inseriti se sono esplicitamente impostati INSERT
nell'istruzione o se i Rn
valori vengono aggiornati in modo dannoso.
SQL-violino-2