Eu tenho uma tabela que atualmente tem valores duplicados em uma coluna.
Não posso remover essas duplicatas errôneas, mas gostaria de impedir que valores não exclusivos adicionais sejam adicionados.
Posso criar um UNIQUE
que não verifique a conformidade existente?
Já tentei usar NOCHECK
mas não obtive sucesso.
Nesse caso, tenho uma tabela que vincula as informações de licenciamento a "CompanyName"
EDIT: Ter várias linhas com o mesmo "CompanyName" é um dado incorreto, mas não podemos remover ou atualizar essas duplicatas neste momento. Uma abordagem é fazer com que os INSERT
s usem um procedimento armazenado que falhará para duplicatas... Se fosse possível que o SQL verificasse a exclusividade por conta própria, seria preferível.
Esses dados são consultados pelo nome da empresa. Para as poucas duplicatas existentes, isso significará que várias linhas serão retornadas e exibidas... Embora isso esteja errado, é aceitável em nosso caso de uso. O objetivo é evitar isso no futuro. Parece-me pelos comentários que tenho que fazer essa lógica nos procedimentos armazenados.
A resposta é sim". Você pode fazer isso com um índice filtrado (veja aqui a documentação).
Por exemplo, você pode fazer:
Isso cria um índice exclusivo, apenas em novas linhas, em vez de nas linhas antigas. Essa formulação específica permitiria duplicatas com valores existentes.
Se você tiver apenas um punhado de duplicatas, poderá fazer algo como:
Sim, você pode fazer isso.
Aqui está uma tabela com duplicatas:
Vamos ignorar os existentes e garantir que nenhuma nova duplicata possa ser adicionada:
Vamos testar esta solução:
O índice exclusivo filtrado é uma ideia brilhante, mas tem uma pequena desvantagem - não importa se você usa a
WHERE identity_column > <current value>
condição ou oWHERE identity_column NOT IN (<list of ids for duplicate values here>)
.Com a primeira abordagem, você ainda poderá inserir dados duplicados no futuro, duplicatas de dados existentes (agora). Por exemplo, se você tiver (mesmo que apenas uma) linha agora com
CompanyName = 'Software Inc.'
, o índice não proibirá a inserção de mais uma linha com o mesmo nome da empresa. Ele só vai proibir se você tentar duas vezes.Com a segunda abordagem, há uma melhoria, o acima não funcionará (o que é bom). No entanto, você ainda poderá inserir mais duplicatas ou duplicatas existentes. Por exemplo, se você tiver (duas ou mais) linhas agora com
CompanyName = 'DoubleData Co.'
, o índice não proibirá a inserção de mais uma linha com o mesmo nome da empresa. Ele só vai proibir se você tentar duas vezes.(Atualização) Isso pode ser corrigido se, para cada nome duplicado, você mantiver fora da lista de exclusão um id. Se, como no exemplo acima, houver 4 linhas com duplicatas
CompanyName = DoubleData Co.
e IDs4,6,8,9
, a lista de exclusão deverá ter apenas 3 desses IDs.Com a segunda abordagem, outra desvantagem é a condição incômoda (o quão incômoda depende de quantas duplicatas existem em primeiro lugar), já que o SQL-Server parece não suportar o
NOT IN
operador naWHERE
parte dos índices filtrados. Consulte SQL-Fiddle . Em vez deWHERE (CompanyID NOT IN (3,7,4,6,8,9))
, você terá que ter algo comoWHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
não tenho certeza se há implicações de eficiência com essa condição, se você tiver centenas de nomes duplicados.Outra solução (semelhante à de @Alex Kuznetsov) é adicionar outra coluna, preenchê-la com números de classificação e adicionar um índice exclusivo, incluindo esta coluna:
Em seguida, a inserção de uma linha com nome duplicado falhará devido à
DEFAULT 1
propriedade e ao índice exclusivo. Isso ainda não é 100% infalível (enquanto o de Alex é). As duplicatas ainda aparecerão se oRn
for definido explicitamente naINSERT
instrução ou se osRn
valores forem atualizados maliciosamente.SQL-Fiddle-2
Outra alternativa é escrever uma função escalar que verifique se um valor já existe na tabela e então chamar essa função a partir de uma restrição de verificação.
Isso fará coisas horríveis para o desempenho.
Estou procurando o mesmo - crie um índice exclusivo não confiável para que os dados incorretos existentes sejam ignorados, mas os novos registros não podem ser duplicados de qualquer coisa que já exista.
Ao ler este tópico, me ocorre que uma solução melhor é escrever um gatilho que verificará [inserido] na tabela pai para duplicatas e, se houver duplicatas entre essas tabelas, ROLLBACK TRAN.