İki sütun birleşimine benzersiz kısıtlama ekleme


149

Bir masam var ve bir şekilde, aynı kişi Personiki kez masama girdi . Şu anda, birincil anahtar sadece bir bağımsız sayıdır, ancak benzersiz olmaya zorlamak istediğim iki alan daha var.

Örneğin, alanlar:

ID  
Name  
Active  
PersonNumber  

Sadece benzersiz bir PersonNumber ve Active = 1 ile 1 kayıt istiyorum.
(Yani iki alanın kombinasyonu benzersiz olması gerekir)

SQL sunucusunda varolan bir tablo üzerinde en iyi yolu nedir Ben başka bir var olan bir değer ile aynı değere sahip bir eklenti yaparsa, bu yüzden uygulama kodumda bu konuda endişelenmenize gerek yok yapabilirim.


3
Uygulama kodunuzda hala endişelenmeniz gerekiyor.
Dan Bracuk

2
Doğru, "bu konuda endişelenmenize gerek yok" ne demek? Bir kullanıcı bir kopya eklemeye çalışırsa ve SQL Server bunu yapmazsa, onlara söylemek istemez misiniz? Uygulamanın bu konuda endişelenmesi gerekiyor gibi görünüyor.
Aaron Bertrand

Yanıtlar:


219

Kopyalarınızı kaldırdıktan sonra:

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

veya

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

Tabii ki, sadece SQL Server'ın satırı eklemeye ve bir istisna döndürmeye izin vermeden önce bu ihlali kontrol etmek genellikle daha iyi olabilir (istisnalar pahalıdır).

http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling

http://www.mssqltips.com/sqlservertip/2632/checking-for-potential-constraint-violations-before-entering-sql-server-try-and-catch-logic/

İstisnaların uygulamada köpürmesini önlemek istiyorsanız, uygulamada değişiklik yapmadan bir INSTEAD OFtetikleyici kullanabilirsiniz :

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

Ancak kullanıcıya eki gerçekleştirmediklerini söylemezseniz, verinin neden orada olmadığını ve herhangi bir istisna bildirilmediğini merak ederler.


Burada DÜZENLEME , tam olarak sorduğunuz şeyi yapan, sorunuzla aynı isimleri bile kullanan ve kanıtlayan bir örnektir. Yukarıdaki fikirlerin kombinasyonun aksine sadece bir sütunu veya diğerini tedavi ettiğini varsaymadan önce denemelisiniz ...

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

Tüm bunlardan sonra tablodaki veriler:

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

Son eklemedeki hata mesajı:

Msg 2627, Seviye 14, Durum 1, Satır 3 BENZERSİZ ANAHTAR kısıtlaması 'uq_Person' ihlali. 'Dbo.Person' nesnesine yinelenen anahtar eklenemiyor. Açıklama sona erdirildi.


3
@leora evet, cevabımın iki sütundaki benzersizliği ele aldığından eminim .
Aaron Bertrand

2
her bir sütunun benzersiz olması değil, sütunların birleşimi (birleştirme) benzersiz olmalıdır. bu mantıklı mı . .
leora

14

Bu GUI'de de yapılabilir:

  1. "Kişi" tablosunun altında, Dizinler'i sağ tıklayın
  2. Tıklama / fareyle üzerine gelme Yeni Dizin
  3. Kümelenmemiş Dizin'i tıklayın ...

resim açıklamasını buraya girin

  1. Varsayılan bir Dizin adı verilir, ancak adını değiştirmek isteyebilirsiniz.
  2. Kontrol Benzersiz onay kutusunu
  3. Click Ekle ... düğmesine

resim açıklamasını buraya girin

  1. Eklenmesini istediğiniz sütunları kontrol edin

resim açıklamasını buraya girin

  1. Her pencerede Tamam'ı tıklayın .

1
Benzersiz Kısıtlama ve Benzersiz Dizin arasındaki fark nedir? Çünkü Benzersiz Kısıtlama ayarladığınızda, 900 Bayt sınırlaması vardır, ancak Benzersiz Dizin'in olmadığı anlaşılıyor.
batmaci

2
Hiçbir şey Referans için bu makaleye bakın: blog.sqlauthority.com/2007/04/26/…
Eli

Benim new Indextıklanabilir değil devre dışı :(
Faisal

4
@Faisal bu tablo için açtığınız sonuçları / tasarım pencerelerini kapatıp tekrar deneyin.
KalaNag


3

Benim durumumda, birçok aktif olmayan ve iki anahtarın sadece bir kombinasyonuna izin vermeliydim, şöyle:

UUL_USR_IDF  UUL_UND_IDF    UUL_ATUAL
137          18             0
137          19             0
137          20             1
137          21             0

Bu işe yarıyor gibi görünüyor:

CREATE UNIQUE NONCLUSTERED INDEX UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL
ON USER_UND(UUL_USR_IDF, UUL_ATUAL)
WHERE UUL_ATUAL = 1;

İşte benim test durumlarım:

SELECT * FROM USER_UND WHERE UUL_USR_IDF = 137

insert into USER_UND values (137, 22, 1) --I CAN NOT => Cannot insert duplicate key row in object 'dbo.USER_UND' with unique index 'UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL'. The duplicate key value is (137, 1).
insert into USER_UND values (137, 23, 0) --I CAN
insert into USER_UND values (137, 24, 0) --I CAN

DELETE FROM USER_UND WHERE UUL_USR_ID = 137

insert into USER_UND values (137, 22, 1) --I CAN
insert into USER_UND values (137, 27, 1) --I CAN NOT => Cannot insert duplicate key row in object 'dbo.USER_UND' with unique index 'UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL'. The duplicate key value is (137, 1).
insert into USER_UND values (137, 28, 0) --I CAN
insert into USER_UND values (137, 29, 0) --I CAN

Test durumunuzu buraya dahil ettiğiniz için teşekkür ederim. Daha fazla Stack Overflow yanıtının benimsenmesini görmek istediğim en iyi uygulama.
Jeremy Caney

0

Çok fazla ekleme sorgunuz varsa, ancak her seferinde bir HATA mesajı istemiyorsanız, bunu yapabilirsiniz:

CREATE UNIQUE NONCLUSTERED INDEX SK01 ON dbo.Person(ID,Name,Active,PersonNumber) 
WITH(IGNORE_DUP_KEY = ON)

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.