두 열의 조합에 고유 제한 조건 추가


149

나는 테이블을 가지고 있고, 같은 사람이 내 Person테이블에 두 번 들어갔다 . 현재 기본 키는 자동 번호 일 뿐이지 만 고유하게 강요하려는 두 개의 다른 필드가 있습니다.

예를 들어, 필드는 다음과 같습니다.

ID  
Name  
Active  
PersonNumber  

고유 한 PersonNumber와 Active = 1을 갖는 1 개의 레코드 만 원합니다.
따라서 두 필드의 조합은 고유해야합니다.

SQL Server의 기존 테이블에서 가장 좋은 방법은 다른 사람이 기존 값과 동일한 값으로 삽입을 수행하면 실패하므로 응용 프로그램 코드에서이를 걱정할 필요가 없습니다.


3
여전히 애플리케이션 코드에서 걱정해야합니다.
Dan Bracuk

2
"걱정할 필요가 없다"는 것은 무엇을 의미합니까? 사용자 복제본을 삽입 하려고 하는데 SQL Server가이를 수행하지 않으면이를 알리고 싶지 않습니까? 응용 프로그램이 걱정해야 할 것 같습니다.
Aaron Bertrand

답변:


219

중복을 제거하면 :

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

또는

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

물론 SQL Server에서 행을 삽입하고 예외를 반환하기 전에 (예외가 비싸기)이 위반을 먼저 확인하는 것이 더 좋습니다.

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/

응용 프로그램을 변경하지 않고 응용 프로그램에 예외가 발생하지 않도록하려면 INSTEAD OF트리거를 사용할 수 있습니다.

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

그러나 사용자에게 삽입을 수행하지 않았다고 알리지 않으면 왜 데이터가없고 예외가보고되지 않았는지 궁금해 할 것입니다.


여기 편집 은 질문과 동일한 이름을 사용하여 요구 사항을 정확하게 수행하고 증명하는 예입니다. 위의 아이디어가 조합이 아닌 하나의 열만 처리한다고 가정하기 전에 시도해야합니다 ...

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

이 모든 후 테이블의 데이터 :

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

마지막 삽입시 오류 메시지 :

메시지 2627, 수준 14, 상태 1, 줄 3 고유 키 제약 조건 'uq_Person'위반 개체 'dbo.Person'에 중복 키를 삽입 할 수 없습니다. 그 진술서는 만료되었습니다.


3
@leora 예, 내 대답이 두 열의 고유성을 처리한다고 확신 합니다.
Aaron Bertrand

2
각 열이 고유해야하는 것이 아니라 열의 조합 (연결)이 고유해야합니다. 말이 돼 . .
leora

14

GUI에서 수행 할 수도 있습니다.

  1. "개인"테이블에서 색인을 마우스 오른쪽 단추로 클릭하십시오.
  2. 새 색인 클릭 / 호버
  3. 비 클러스터형 인덱스 ...를 클릭하십시오 .

여기에 이미지 설명을 입력하십시오

  1. 기본 색인 이름 이 제공되지만 변경할 수도 있습니다.
  2. 확인 고유의 체크 박스를
  3. 추가 ... 버튼을 클릭 하십시오

여기에 이미지 설명을 입력하십시오

  1. 포함하려는 열을 확인하십시오.

여기에 이미지 설명을 입력하십시오

  1. 각 창에서 확인 을 클릭하십시오 .

1
Unique Constraint와 Unique Index의 차이점은 무엇입니까? Unique Constraint를 설정하면 900 바이트 제한이 있지만 Unique Index에는없는 것처럼 보입니다.
batmaci

2
아무것도이 기사를 참조하십시오 : blog.sqlauthority.com/2007/04/26/…
Eli

new Index클릭 할 수 없습니다 :(
Faisal

4
@Faisal은 해당 테이블에 대해 열린 결과 / 디자인 창을 닫고 다시 시도하십시오.
KalaNag

@Faisal 이것을 확인하십시오 : stackoverflow.com/a/60014466/4654957
Diego Venâncio

3

필자의 경우 다음과 같이 많은 비활성을 허용하고 두 키의 조합 하나만 활성화해야했습니다.

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

이것은 작동하는 것 같습니다 :

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

내 테스트 사례는 다음과 같습니다.

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

테스트 사례를 여기에 포함시켜 주셔서 감사합니다. 이것이 스택 오버플로 답변이 더 많이 채택되고 싶은 모범 사례입니다.
Jeremy Caney

0

그리고 많은 삽입 쿼리가 있지만 매번 ERROR 메시지를 생성하고 싶지 않다면 할 수 있습니다.

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

여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.