Tengo una tabla que actualmente tiene valores duplicados en una columna.
No puedo eliminar estos duplicados erróneos, pero me gustaría evitar que se agreguen valores adicionales no únicos.
¿Puedo crear uno UNIQUE
que no verifique el cumplimiento existente?
He intentado usar NOCHECK
pero no tuve éxito.
En este caso, tengo una tabla que vincula la información de licencia a "CompanyName"
EDITAR: Tener varias filas con el mismo "CompanyName" son datos incorrectos, pero no podemos eliminar o actualizar esos duplicados en este momento. Un enfoque es hacer que los INSERT
s utilicen un procedimiento almacenado que fallará para los duplicados ... Si fuera posible que SQL verificara la unicidad por sí mismo, sería preferible.
Estos datos se consultan por el nombre de la empresa. Para los pocos duplicados existentes, esto significará que se devuelven y muestran varias filas ... Si bien esto es incorrecto, es aceptable en nuestro caso de uso. El objetivo es prevenirlo en el futuro. Me parece por los comentarios que tengo que hacer esta lógica en los procedimientos almacenados.
Respuestas:
La respuesta es sí". Puede hacerlo con un índice filtrado (consulte aquí la documentación).
Por ejemplo, puedes hacer:
Esto crea un índice único, solo en filas nuevas , en lugar de en las filas antiguas. Esta formulación particular permitiría duplicados con valores existentes.
Si solo tiene un puñado de duplicados, puede hacer algo como:
fuente
Si tu puedes hacerlo.
Aquí hay una tabla con duplicados:
Ignoremos los existentes y asegurémonos de que no se puedan agregar nuevos duplicados:
Probemos esta solución:
fuente
UNIQUE
restricción en una columna anulable asegura que haya como máximo un únicoNULL
valor. El estándar SQL (y casi todos los demás DBMS SQL) dice que debe permitir cualquier número deNULL
valores (es decir, la restricción debe ignorar los valores nulos).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 elWHERE 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 ID4,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 laWHERE
parte de los índices filtrados. Ver SQL-Fiddle . En lugar de esoWHERE (CompanyID NOT IN (3,7,4,6,8,9))
, tendrá que tener algo así comoWHERE (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:
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 siRn
se establece explícitamente en laINSERT
declaración o si losRn
valores se actualizan maliciosamente.SQL-Fiddle-2
fuente
Otra alternativa es escribir una función escalar que verifique si ya existe un valor en la tabla y luego llamar a esa función desde una restricción de verificación.
Esto hará cosas horribles para el rendimiento.
fuente
Estoy buscando lo mismo: cree un índice único no confiable para que se ignoren los datos incorrectos existentes, pero los nuevos registros no pueden ser duplicados de nada que ya exista.
Mientras leo este hilo, se me ocurre que una mejor solución es escribir un disparador que verifique [insertado] en la tabla principal para ver si hay duplicados, y si existen duplicados entre esas tablas, ROLLBACK TRAN.
fuente