sql >> Base de Datos >  >> RDS >> Sqlserver

Agregar restricción única a la combinación de dos columnas

Una vez que haya eliminado su(s) duplicado(s):

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

o

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

Por supuesto, a menudo puede ser mejor verificar primero esta infracción, antes de dejar que SQL Server intente insertar la fila y devolver una excepción (las excepciones son costosas).

  • Impacto en el rendimiento de diferentes técnicas de manejo de errores

  • Comprobación de posibles violaciones de restricciones antes de ingresar TRY/CATCH

Si desea evitar que aparezcan excepciones en la aplicación, sin realizar cambios en la aplicación, puede usar un INSTEAD OF disparador:

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

Pero si no le dice al usuario que no realizó la inserción, se preguntará por qué los datos no están allí y no se informó ninguna excepción.

EDITAR aquí hay un ejemplo que hace exactamente lo que está pidiendo, incluso usando los mismos nombres que su pregunta, y lo prueba. Debe probarlo antes de asumir que las ideas anteriores solo tratan una columna u otra en lugar de la combinación...

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

Datos en la tabla después de todo esto:

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

Mensaje de error en la última inserción:

Mensaje 2627, Nivel 14, Estado 1, Línea 3 Violación de la restricción CLAVE ÚNICA 'uq_Person'. No se puede insertar una clave duplicada en el objeto 'dbo.Person'. La declaración ha sido cancelada.

También escribí en un blog más recientemente sobre una solución para aplicar una restricción única a dos columnas en cualquier orden :

  • Hacer cumplir una restricción única donde el orden no importa