Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Adicionar restrição exclusiva à combinação de duas colunas


Depois de remover sua(s) duplicata(s):
ALTER TABLE dbo.yourtablename
  ADD CONSTRAINT uq_yourtablename UNIQUE(column1, column2);

ou
CREATE UNIQUE INDEX uq_yourtablename
  ON dbo.yourtablename(column1, column2);

Claro, muitas vezes pode ser melhor verificar essa violação primeiro, antes de apenas deixar o SQL Server tentar inserir a linha e retornar uma exceção (as exceções são caras).

  • Impacto no desempenho de diferentes técnicas de tratamento de erros

  • Verificando possíveis violações de restrição antes de inserir TRY/CATCH

Se você quiser evitar que exceções cheguem ao aplicativo, sem fazer alterações no aplicativo, você pode usar um INSTEAD OF acionar:
CREATE TRIGGER dbo.BlockDuplicatesYourTable
 ON dbo.YourTable
 INSTEAD OF INSERT
AS
BEGIN
  SET NOCOUNT ON;

  IF NOT EXISTS (SELECT 1 FROM inserted AS i 
    INNER JOIN dbo.YourTable AS t
    ON i.column1 = t.column1
    AND i.column2 = t.column2
  )
  BEGIN
    INSERT dbo.YourTable(column1, column2, ...)
      SELECT column1, column2, ... FROM inserted;
  END
  ELSE
  BEGIN
    PRINT 'Did nothing.';
  END
END
GO

Mas se você não disser ao usuário que ele não executou a inserção, eles vão se perguntar por que os dados não estão lá e nenhuma exceção foi relatada.

EDITAR aqui está um exemplo que faz exatamente o que você está pedindo, mesmo usando os mesmos nomes da sua pergunta, e prova isso. Você deve experimentá-lo antes de assumir que as ideias acima tratam apenas uma coluna ou outra em oposição à combinação ...
USE tempdb;
GO

CREATE TABLE dbo.Person
(
  ID INT IDENTITY(1,1) PRIMARY KEY,
  Name NVARCHAR(32),
  Active BIT,
  PersonNumber INT
);
GO

ALTER TABLE dbo.Person 
  ADD CONSTRAINT uq_Person UNIQUE(PersonNumber, Active);
GO

-- succeeds:
INSERT dbo.Person(Name, Active, PersonNumber)
  VALUES(N'foo', 1, 22);
GO

-- succeeds:
INSERT dbo.Person(Name, Active, PersonNumber)
  VALUES(N'foo', 0, 22);
GO

-- fails:
INSERT dbo.Person(Name, Active, PersonNumber)
  VALUES(N'foo', 1, 22);
GO

Dados na tabela depois de tudo isso:
ID   Name   Active PersonNumber
---- ------ ------ ------------
1    foo    1      22
2    foo    0      22

Mensagem de erro na última inserção:

Msg 2627, Level 14, State 1, Line 3Violation of UNIQUE KEY constraint 'uq_Person'. Não é possível inserir a chave duplicada no objeto 'dbo.Person'. A instrução foi encerrada.

Também escrevi mais recentemente sobre uma solução para aplicar uma restrição exclusiva a duas colunas em qualquer ordem :
  • Aplicar uma restrição exclusiva onde a ordem não importa