Eu tenho uma tabela que atualmente tem valores duplicados em uma coluna.
Não consigo remover essas duplicatas incorretas, mas gostaria de impedir que valores adicionais não exclusivos sejam adicionados.
Posso criar um UNIQUE
que não verifique a conformidade existente?
Eu tentei usar, NOCHECK
mas não obtive sucesso.
Nesse caso, tenho uma tabela que vincula informações de licenciamento a "CompanyName"
EDIT: Ter várias linhas com o mesmo "CompanyName" é um dado inválido, mas não podemos remover ou atualizar essas duplicatas no momento. Uma abordagem é fazer com que eles INSERT
usem um procedimento armazenado que falhe para duplicatas ... Se fosse possível que o SQL verifique a exclusividade por si só, isso seria preferível.
Esses dados são consultados pelo nome da empresa. Para as poucas duplicatas existentes, isso significa que várias linhas são retornadas e exibidas ... Embora isso esteja errado, é aceitável em nosso caso de uso. O objetivo é evitá-lo no futuro. Parece-me pelos comentários que eu tenho que fazer essa lógica nos procedimentos armazenados.
Respostas:
A resposta é sim". Você pode fazer isso com um índice filtrado (veja aqui para documentação).
Por exemplo, você pode fazer:
Isso cria um índice exclusivo, apenas em novas linhas, e não nas linhas antigas. Esta formulação específica permitiria duplicatas com os valores existentes.
Se você tiver apenas algumas cópias, poderá fazer algo como:
fonte
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:
fonte
UNIQUE
restrição em uma coluna anulável garante que haja no máximo um únicoNULL
valor. O padrão SQL (e quase todos os outros DBMSs SQL) diz que deve permitir qualquer número deNULL
valores (ou seja, a restrição deve ignorar valores nulos).O índice exclusivo filtrado é uma idéia brilhante, mas possui 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, duplicados dos dados existentes (agora). Por exemplo, se você tiver (mesmo apenas uma) linha agora
CompanyName = 'Software Inc.'
, o índice não proibirá a inserção de mais uma linha com o mesmo nome da empresa. Só o 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. Só o proibirá se você tentar duas vezes.(Atualização) Isso pode ser corrigido se, para cada nome duplicado, você mantiver fora da lista de exclusões um ID. Se, como no exemplo acima, houver 4 linhas com
CompanyName = DoubleData Co.
IDs e duplicados4,6,8,9
, a lista de exclusão deverá ter apenas 3 desses IDs.Com a segunda abordagem, outra desvantagem é a condição complicada (quanto pesada depende de quantas duplicatas existem), pois o SQL-Server parece não oferecer suporte ao
NOT IN
operador naWHERE
parte dos índices filtrados. Veja SQL-Fiddle . Em vez dissoWHERE (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 à do @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 serãoRn
inseridas se estiver explicitamente definido naINSERT
instrução ou se osRn
valores forem atualizados com códigos maliciosos.SQL-Fiddle-2
fonte
Outra alternativa é escrever uma função escalar que verifique se já existe um valor na tabela e, em seguida, chame essa função a partir de uma restrição de verificação.
Isso fará coisas horríveis para o desempenho.
fonte
Estou procurando o mesmo - crie um índice exclusivo não confiável para que os dados ruins existentes sejam ignorados, mas novos registros não podem ser duplicados de qualquer coisa que já exista.
Ao ler este tópico, me parece que uma solução melhor é escrever um gatilho que verifique se há duplicatas na tabela pai, e se existem duplicatas entre essas tabelas, ROLLBACK TRAN.
fonte