AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 43823
Accepted
Matthew
Matthew
Asked: 2013-06-05 09:41:59 +0800 CST2013-06-05 09:41:59 +0800 CST 2013-06-05 09:41:59 +0800 CST

Posso adicionar uma restrição exclusiva que ignore as violações existentes?

  • 772

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 UNIQUEque não verifique a conformidade existente?

Já tentei usar NOCHECKmas 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 INSERTs 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.

sql-server database-design
  • 5 5 respostas
  • 52936 Views

5 respostas

  • Voted
  1. Best Answer
    Gordon Linoff
    2013-06-05T10:28:38+08:002013-06-05T10:28:38+08:00

    A resposta é sim". Você pode fazer isso com um índice filtrado (veja aqui a documentação).

    Por exemplo, você pode fazer:

    create unique index t_col on t(col) where id > 1000;
    

    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:

    create unique index t_col on t(col) where id not in (<list of ids for duplicate values here>);
    
    • 39
  2. A-K
    2013-06-05T13:06:03+08:002013-06-05T13:06:03+08:00

    Sim, você pode fazer isso.

    Aqui está uma tabela com duplicatas:

    CREATE TABLE dbo.Party
      (
        ID INT NOT NULL
               IDENTITY ,
        CONSTRAINT PK_Party PRIMARY KEY ( ID ) ,
        Name VARCHAR(30) NOT NULL
      ) ;
    GO
    
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Frodo Baggins' ),
            ( 'Luke Skywalker' ),
            ( 'Luke Skywalker' ),
            ( 'Harry Potter' ) ;
    GO
    

    Vamos ignorar os existentes e garantir que nenhuma nova duplicata possa ser adicionada:

    -- Add a new column to mark grandfathered duplicates.
    ALTER TABLE dbo.Party ADD IgnoreThisDuplicate INT NULL ;
    GO
    
    -- The *first* instance will be left NULL.
    -- *Secondary* instances will be set to their ID (a unique value).
    UPDATE  dbo.Party
    SET     IgnoreThisDuplicate = ID
    FROM    dbo.Party AS my
    WHERE   EXISTS ( SELECT *
                     FROM   dbo.Party AS other
                     WHERE  other.Name = my.Name
                            AND other.ID < my.ID ) ;
    GO
    
    -- This constraint is not strictly necessary.
    -- It prevents granting further exemptions beyond the ones we made above.
    ALTER TABLE dbo.Party WITH NOCHECK
    ADD CONSTRAINT CHK_Party_NoNewExemptions 
    CHECK(IgnoreThisDuplicate IS NULL);
    GO
    
    SELECT * FROM dbo.Party;
    GO
    
    -- **THIS** is our pseudo-unique constraint.
    -- It works because the grandfathered duplicates have a unique value (== their ID).
    -- Non-grandfathered records just have NULL, which is not unique.
    CREATE UNIQUE INDEX UNQ_Party_UniqueNewNames ON dbo.Party(Name, IgnoreThisDuplicate);
    GO
    

    Vamos testar esta solução:

    -- cannot add a name that exists
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Frodo Baggins' );
    
    Cannot insert duplicate key row in object 'dbo.Party' with unique index 'UNQ_Party_UniqueNewNames'.
    
    -- cannot add a name that exists and has an ignored duplicate
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Luke Skywalker' );
    
    Cannot insert duplicate key row in object 'dbo.Party' with unique index 'UNQ_Party_UniqueNewNames'.
    
    
    -- can add a new name 
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Hamlet' );
    
    -- but only once
    INSERT  INTO dbo.Party
            ( Name )
    VALUES  ( 'Hamlet' );
    
    Cannot insert duplicate key row in object 'dbo.Party' with unique index 'UNQ_Party_UniqueNewNames'.
    
    • 25
  3. ypercubeᵀᴹ
    2013-06-05T13:00:38+08:002013-06-05T13:00:38+08:00

    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 o WHERE 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 IDs 4,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 INoperador na WHEREparte dos índices filtrados. Consulte SQL-Fiddle . Em vez de WHERE (CompanyID NOT IN (3,7,4,6,8,9)), você terá que ter algo como WHERE (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:

    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) ; 
    

    Em seguida, a inserção de uma linha com nome duplicado falhará devido à DEFAULT 1propriedade e ao índice exclusivo. Isso ainda não é 100% infalível (enquanto o de Alex é). As duplicatas ainda aparecerão se o Rnfor definido explicitamente na INSERTinstrução ou se os Rnvalores forem atualizados maliciosamente.

    SQL-Fiddle-2

    • 17
  4. Greenstone Walker
    2013-06-05T17:45:02+08:002013-06-05T17:45:02+08:00

    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.

    • -2
  5. Brad
    2015-10-30T11:08:06+08:002015-10-30T11:08:06+08:00

    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.

    • -2

relate perguntas

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Quais são algumas maneiras de implementar um relacionamento muitos-para-muitos em um data warehouse?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Conceder acesso a todas as tabelas para um usuário

    • 5 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve