El índice único filtrado es una idea brillante, pero tiene una desventaja menor, no importa si usa la WHERE identity_column > <current value>
condición o el WHERE identity_column NOT IN (<list of ids for duplicate values here>)
.
Con el primer enfoque, aún podrá insertar datos duplicados en el futuro, duplicados de datos existentes (ahora). Por ejemplo, si tiene (incluso una) fila ahora con CompanyName = 'Software Inc.'
, el índice no prohibirá la inserción de una fila más con el mismo nombre de la compañía. Solo lo prohibirá si lo intentas dos veces.
Con el segundo enfoque hay una mejora, lo anterior no funcionará (lo cual es bueno). Sin embargo, aún podrá insertar más duplicados o duplicados existentes. Por ejemplo, si tiene (dos o más) filas ahora con CompanyName = 'DoubleData Co.'
, el índice no prohibirá la inserción de una fila más con el mismo nombre de la compañía. Solo lo prohibirá si lo intentas dos veces.
(Actualización) Esto se puede corregir si por cada nombre duplicado, se mantiene fuera de la lista de exclusión un ID. Si, como en el ejemplo anterior, hay 4 filas con duplicados CompanyName = DoubleData Co.
e ID 4,6,8,9
, la lista de exclusión debe tener solo 3 de estos ID.
Con el segundo enfoque, otra desventaja es la condición engorrosa (cuánto engorroso depende de cuántos duplicados hay en primer lugar), ya que SQL-Server parece no admitir el NOT IN
operador en la WHERE
parte de los índices filtrados. Ver SQL-Fiddle . En lugar de eso WHERE (CompanyID NOT IN (3,7,4,6,8,9))
, tendrá que tener algo así como WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
no estoy seguro si hay implicaciones de eficiencia con tal condición, si tiene cientos de nombres duplicados.
Otra solución (similar a la de @Alex Kuznetsov) es agregar otra columna, llenarla con números de rango y agregar un índice único que incluya esta columna:
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) ;
Luego, la inserción de una fila con nombre duplicado fallará debido a la DEFAULT 1
propiedad y al índice único. Esto todavía no es 100% infalible (mientras que Alex lo es). Los duplicados seguirán apareciendo si Rn
se establece explícitamente en la INSERT
declaración o si los Rn
valores se actualizan maliciosamente.
SQL-Fiddle-2