sql >> Databasteknik >  >> RDS >> Sqlserver

Lägg till en unik begränsning för kombinationen av två kolumner

När du har tagit bort dina dubbletter:

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

eller

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

Naturligtvis kan det ofta vara bättre att kolla efter denna överträdelse först, innan du bara låter SQL Server försöka infoga raden och returnera ett undantag (undantag är dyra).

  • Prestandapåverkan av olika felhanteringstekniker

  • Söker efter potentiella överträdelser av begränsningar innan du går in i TRY/CATCH

Om du vill förhindra att undantag bubblar upp till applikationen, utan att göra ändringar i applikationen, kan du använda en INSTEAD OF trigger:

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

Men om du inte berättar för användaren att de inte utförde infogningen kommer de att undra varför data inte finns där och inget undantag rapporterades.

REDIGERA här är ett exempel som gör precis vad du efterfrågar, även med samma namn som din fråga, och bevisar det. Du bör prova det innan du antar att idéerna ovan bara behandlar den ena eller den andra kolumnen i motsats till kombinationen...

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

Data i tabellen efter allt detta:

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

Felmeddelande på den senaste infogningen:

Medd. 2627, Nivå 14, Tillstånd 1, Rad 3 Brott mot UNIQUE KEY-begränsningen 'uq_Person'. Det går inte att infoga dubblettnyckel i objektet 'dbo.Person'. Uttrycket har avslutats.

Jag bloggade också mer nyligen om en lösning för att tillämpa en unik begränsning på två kolumner i valfri ordning :

  • Tillämpa en unik begränsning där ordning inte spelar någon roll


  1. Vanliga Postgres-uppgifter på CentOS 7

  2. MySQL CEILING() Funktion – Runda uppåt till närmaste heltal

  3. NULL Complexities – Del 2

  4. Kan jag återställa en enskild tabell från en fullständig mysql mysqldump-fil?