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 / 339832
Accepted
Max
Max
Asked: 2024-05-27 22:04:59 +0800 CST2024-05-27 22:04:59 +0800 CST 2024-05-27 22:04:59 +0800 CST

Aplicar combinação não exclusiva de colunas, onde a combinação é necessária

  • 772

Eu tenho as seguintes colunas (e mais não relacionadas) em minha tabela de banco de dados MSSQL Id: ImageUrle ImageId. A combinação de ImageUrle ImageIdpode ocorrer várias vezes. ImageUrlpertence ImageIde vice-versa.

Os exemplos a seguir usam valores fictícios para maior clareza, para a tabela de banco de dados real ImageId: int e ImageUrl: nvarchar são usados ​​como tipos de dados.

ImageId= aque pertence a ImageUrl= a.compode ocorrer várias vezes, mas ImageId= anão pode ser usado para outros ImageUrl.

ImageUrl= a.compode ocorrer múltiplas vezes com o mesmo ImageId, mas ImageUrl= a.comnão pode ocorrer com múltiplos ImageIdcomo ae b.

Os seguintes dados devem ser possíveis:

Eu ia ID da imagem Imagem URL
1 a a.com
2 a a.com
3 b b.com

Os dois exemplos a seguir não são permitidos:

Eu ia ID da imagem Imagem URL
1 a a.com
2 b a.com
Eu ia ID da imagem Imagem URL
1 a a.com
2 a b.com

Não sei e não encontrei soluções MSSQL para isso.

Pergunta: Existe uma solução para impor isso no MSSQL? E existe uma palavra/termo para esta restrição/aplicação?

Editar: isto é para meu banco de dados existente com muitos dados, onde esta tabela é a tabela "primária". Prefiro não alterar a estrutura desta tabela alterando ou removendo colunas. Adicionar colunas está bem. É por isso que a resposta de @LeppyR64 não seria uma solução para o meu caso de uso.

sql-server
  • 3 3 respostas
  • 409 Views

3 respostas

  • Voted
  1. Lennart - Slava Ukraini
    2024-05-28T16:59:48+08:002024-05-28T16:59:48+08:00

    Como alguém sugeriu, o melhor é consertar o modelo. Muitas vezes é possível usar view + em vez de gatilhos para compatibilidade com versões anteriores.

    Se não for possível e seu objetivo for evitar a adição de dados malformados, você poderá usar um gatilho:

    create table T
    ( someid int not null primary key
    , imageid char(1) not null
    , imageurl varchar(100) not null
    );  
    
    CREATE TRIGGER trg ON T  
    FOR INSERT
    AS
    IF  EXISTS(SELECT NULL FROM T x 
               JOIN inserted y 
                   ON x.imageid = y.imageid 
                   AND x.imageurl <> y.imageurl)
    BEGIN
            RAISERROR('Image exists with conflicting url', 16, 1)
            ROLLBACK TRAN
            RETURN
    END;
    

    Você provavelmente deveria adicionar um para a atualização também

    insert into T (someid, imageid, imageurl) 
    values (1, 'a', 'a.com'), (2, 'a', 'a.com'), (3, 'b', 'b.com');
    
    insert into T (someid, imageid, imageurl)
    values (4, 'b', 'a.com');
    
    Msg 50000 Level 16 State 1 Line 10
    Image exists with conflicting url
    Msg 3609 Level 16 State 1 Line 1
    The transaction ended in the trigger. The batch has been aborted.
    

    Violino

    • 6
  2. Best Answer
    Paul White
    2024-05-28T18:48:14+08:002024-05-28T18:48:14+08:00

    Usar um modelo de banco de dados relacional teria evitado esse problema. A dificuldade de converter os dados e adaptar o aplicativo é o preço a pagar pelo design inicial incorreto.

    Dito isto, você pode impor a restrição necessária ao arranjo existente usando uma visão materializada:

    CREATE TABLE dbo.T 
    (
        Id integer NOT NULL,
        ImageId char(1) NOT NULL, 
        ImageUrl varchar(900) NOT NULL
    );
    GO
    CREATE OR ALTER VIEW dbo.ValidComboT
    WITH SCHEMABINDING AS
    SELECT 
        ImageId, 
        ImageUrl,
        NumRows = COUNT_BIG(*)
    FROM dbo.T
    GROUP BY 
        ImageId,
        ImageUrl;
    GO
    CREATE UNIQUE CLUSTERED INDEX
        [CUQ dbo.ValidComboT ImageId, ImageUrl]
    ON dbo.ValidComboT 
        (ImageId, ImageUrl);
    GO
    CREATE UNIQUE NONCLUSTERED INDEX
        [UQ dbo.ValidComboT ImageId]
    ON dbo.ValidComboT 
        (ImageId);
    GO
    CREATE UNIQUE NONCLUSTERED INDEX
        [UQ dbo.ValidComboT ImageUrl]
    ON dbo.ValidComboT 
        (ImageUrl);
    GO
    

    Teste:

    -- Succeeds
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (1, 'a', 'a.com');
    
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (2, 'a', 'a.com');
    
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (3, 'b', 'b.com');
    GO
    -- Reset
    DELETE dbo.T;
    
    -- Fails
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (1, 'a', 'a.com');
    
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (2, 'b', 'a.com');
    GO
    -- Reset
    DELETE dbo.T;
    
    -- Fails
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (1, 'a', 'a.com');
    
    INSERT dbo.T (Id, ImageId, ImageUrl) 
    VALUES (2, 'a', 'b.com');
    

    Saída:

    (3 rows affected)
    
    Msg 2601, Level 14, State 1
    Cannot insert duplicate key row in object 'dbo.ValidComboT' 
      with unique index 'UQ dbo.ValidComboT ImageUrl'. 
      The duplicate key value is (a.com).
    The statement has been terminated.
    
    Msg 2601, Level 14, State 1
    Cannot insert duplicate key row in object 'dbo.ValidComboT' 
      with unique index 'UQ dbo.ValidComboT ImageId'. 
      The duplicate key value is (a).
    The statement has been terminated.
    

    O limite para o comprimento da chave de índice clusterizado é de 900 bytes, portanto, isso só funcionará se a combinação de ImageId e ImageUrl se ajustar a isso.

    Esta solução adiciona um pequeno custo a cada modificação de dados que afeta a visualização. Há também um requisito de armazenamento para as linhas materializadas. Por outro lado, você pode achar as informações da visualização úteis para outras consultas. O mecanismo de banco de dados também pode fazer uso dele.

    db<> demonstração de violino

    Considerações

    O mecanismo de banco de dados cuida de todos os detalhes necessários para manter a visão materializada sincronizada com a tabela base.

    Se você codificar sua própria solução (por exemplo, usando um gatilho), você assume a responsabilidade de cobrir todos os casos extremos que podem ocorrer sob alta simultaneidade. Isso nem sempre é trivial. Duas sessões podem verificar uma linha conflitante ao mesmo tempo, concluir que ela não existe e, em seguida, ambas inserem com base nisso, resultando em uma duplicata não detectada.

    Por outro lado, a segurança extra incorporada na manutenção da visualização tem um custo para a simultaneidade potencial. Se muitas linhas na tabela base forem resumidas em uma única linha de visualização, bloqueios adicionais poderão ocorrer devido a essa 'concentração de bloqueio'. Os impasses também são uma possibilidade, embora a indexação correta possa mitigar isso.

    Manter uma visão indexada normalmente é um pouco mais rápido do que um acionador porque os operadores de plano necessários para manter a visão são inseridos no plano para a instrução de alteração de dados. Um gatilho requer controle de versão de linha e sua lógica é executada em um contexto SQL separado. O custo é semelhante à execução de comandos SQL adicionais.

    A visualização materializada valida todos os dados da tabela base quando ela é criada. Os gatilhos só se aplicam a linhas adicionadas ou modificadas depois que os gatilhos são criados e enquanto permanecem ativados. As inserções em massa na tabela ignorarão os gatilhos de disparo por padrão.

    Todas estas são generalizações e não uma lista completa das considerações. Você precisa testar as diversas abordagens em seu ambiente. Ou faça a transição para um bom design onde nenhuma dessas brincadeiras seja necessária.

    • 6
  3. LeppyR64
    2024-05-27T23:43:32+08:002024-05-27T23:43:32+08:00

    Crie uma Imagesmesa. ImageIdé a chave primária. Crie um índice exclusivo adicional na ImageUrlcoluna.

    ID da imagem Imagem URL
    a a.com
    b b.com

    A tabela Data pode então ter Id, e ImageIdcomo chave estrangeira para a tabela Images.

    Eu ia ID da imagem
    1 a
    2 a
    3 b
    • 4

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • 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?

  • 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

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 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

    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
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • 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
    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