Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Ajouter une contrainte unique à la combinaison de deux colonnes

Une fois que vous avez supprimé votre ou vos doublons :

ALTER TABLE dbo.yourtablename
  ADD CONSTRAINT uq_yourtablename UNIQUE(column1, column2);

ou

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

Bien sûr, il peut souvent être préférable de vérifier d'abord cette violation, avant de laisser SQL Server essayer d'insérer la ligne et de renvoyer une exception (les exceptions coûtent cher).

  • Impact sur les performances des différentes techniques de gestion des erreurs

  • Vérification des violations potentielles des contraintes avant d'entrer TRY/CATCH

Si vous souhaitez empêcher les exceptions de remonter jusqu'à l'application, sans apporter de modifications à l'application, vous pouvez utiliser un INSTEAD OF déclencheur :

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

Mais si vous ne dites pas à l'utilisateur qu'il n'a pas effectué l'insertion, il se demandera pourquoi les données ne sont pas là et aucune exception n'a été signalée.

MODIFIER voici un exemple qui fait exactement ce que vous demandez, même en utilisant les mêmes noms que votre question, et le prouve. Vous devriez l'essayer avant de supposer que les idées ci-dessus ne traitent qu'une colonne ou l'autre par opposition à la combinaison...

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

Données dans le tableau après tout cela :

ID   Name   Active PersonNumber
---- ------ ------ ------------
1    foo    1      22
2    foo    0      22

Message d'erreur lors de la dernière insertion :

Msg 2627, niveau 14, état 1, ligne 3Violation de la contrainte UNIQUE KEY 'uq_Person'. Impossible d'insérer une clé en double dans l'objet 'dbo.Person'. L'instruction a été terminée.

J'ai également blogué plus récemment sur une solution pour appliquer une contrainte unique à deux colonnes dans n'importe quel ordre :

  • Appliquer une contrainte unique là où l'ordre n'a pas d'importance