NULL 열에 고유 인덱스를 만드는 방법은 무엇입니까?


101

SQL Server 2005를 사용하고 있습니다. NULLS를 허용하면서 열의 값을 고유하게 제한하고 싶습니다.

내 현재 솔루션에는 다음과 같은 뷰의 고유 인덱스가 포함됩니다.

CREATE VIEW vw_unq WITH SCHEMABINDING AS
    SELECT Column1
      FROM MyTable
     WHERE Column1 IS NOT NULL

CREATE UNIQUE CLUSTERED INDEX unq_idx ON vw_unq (Column1)

더 좋은 아이디어가 있습니까?


16
SQL 2008을 사용할 기회가 없습니까? 당신은 '어디'를 사용하여 필터링 된 인덱스를 만들 수 있습니다
Simon_Weaver

3
고유 한 것이 아니라 NULL을 허용하는 것이 아니라 고유 한 것을 의미하는 것 같지만 여러 NULL을 포함합니다 . 그렇지 않으면 NULL이 다른 값과 같이 인덱싱되고 고유성 제약 조건이 예상대로 작동합니다. @pst가 아래 주석에서 언급했듯이 SQL 표준에 따르지 않습니다.
Suncat2000

답변:


26

고유의 목적을 위반하므로 그렇게 할 수 없습니다.

그러나이 사람은 적절한 해결 방법을 가지고있는 것 같습니다. http://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html


2
: 그것은 당신이 실제로 (부분적으로) 여기에서 저작자없이 복사 된 제공된 링크의 내용 보인다 decipherinfosys.wordpress.com/2007/11/30/...
톰 JUERGENS

77
나는 그것이 "유일성의 목적에 위배된다"는 것에 동의하지 않는다. NULL은 SQL의 특별한 값 (다양한면에서 NaN과 유사)이며 그에 따라 처리되어야한다. 실제로 SQL Server에서 다양한 SQL 사양을 준수하지 못하는 것은 실패입니다 . 다음은 가치에 대한 "올바른 구현"요청에 대한 링크입니다. connect.microsoft.com/SQLServer/feedback/details/299229/… .

5
2008 년에 참조를 위해 CREATE UNIQUE INDEX foo ON dbo.bar (key) WHERE key IS NOT NULL;
niico

2
"유일성의 목적을 위반 함"에도 동의하지 않습니다. NULL은 NULL과 같지 않으므로 nullable 열에 고유 인덱스를 만들고 여러 null을 삽입 할 수 있어야합니다.
Wodzu

105

SQL Server 2008을 사용하여 필터링 된 인덱스를 만들 수 있습니다 : http://msdn.microsoft.com/en-us/library/cc280372.aspx . (Simon이 이것을 주석으로 추가 한 것을 보았지만 주석을 쉽게 놓칠 수 있으므로 자체 답변이 필요하다고 생각했습니다.)

또 다른 옵션은 고유성을 확인하는 트리거이지만 성능에 영향을 미칠 수 있습니다.


84
create unique index UIX on MyTable (Column1) where Column1 is not null
Jørn Schou-Rode

1
참고 : 현재 SQL Server Management Studio를 사용하면 나중에 혼란거야 테이블을 수정, 그래서 만약 이러한 인덱스를 만드는 방법을 알고 그렇게 그것을 다시 기억 드롭을 시도하지 않는 것
Simon_Weaver

3
Microsoft가이를 지원하기 위해 SSMS를 업데이트 한 것 같습니다. SSMS 10.50.1617이 있고 인덱스 속성 대화 상자에서 필터 페이지를 선택하여 필터를 편집 할 수 있습니다. 예 : "([Column1] IS NOT NULL)"
Phil Haselden 2011-08-09

5
인덱스에서 여러 null을 허용하고 인덱스에서 null을 필터링하는 것은 별개의 것입니다. 인덱스를 필터링하면 실제로 인덱스에서 레코드가 제외되는 반면 다른 솔루션은 null을 유용한 고유 값으로 변환합니다. 차이점을 인식하십시오.
Suncat2000

당신이 그와 같은 필터링 된 인덱스가있는 테이블에 저장 프로 시저를 사용하는 경우, 그 확인 ANSI_NULLS입니다 ON데이터를 삽입 할 때 그렇지 않으면 오류가 발생합니다.
Arne

71

계산 된 열 트릭은 "널 버스터"로 널리 알려져 있습니다. 내 메모 신용 Steve Kass :

CREATE TABLE dupNulls (
pk int identity(1,1) primary key,
X  int NULL,
nullbuster as (case when X is null then pk else 0 end),
CONSTRAINT dupNulls_uqX UNIQUE (X,nullbuster)
)

이것은 멋진 속임수처럼 보입니다. 이상하게 nullbuster를 검색해도 너무 많은 정보가 표시되지 않습니다. PK를 사용하여 색인에 더 많은 작업을 제공하는 경우 null에 대해 1과 0의 계산 열이 아니라 검색 속도를 높이는 데 이것이 유용할지 궁금합니다. 이번 주말에 큰 테이블에서 테스트하러갑니다.
David Storfer 2011 년

@DavidStorfer, 두 테이블의 ID간에 ​​충돌이 발생할 수 있기 때문에 그렇게 할 수 없습니다.
user393274

개선 : ISNULL (X, CONVERT (VARCHAR (10), pk))
Faiz 2014 년

5
@Faiz : 개선은 보는 사람의 눈입니다. 나는 원래의 모습을 선호합니다.
onedaywhen

@NunoG, 이것은 사라질 수있는 외부 사이트를 연결하는 대신 요구 사항을 준수하는 좋은 솔루션을 제공하기 때문에 허용되는 대답이어야합니다.
Frédéric

-3

엄밀히 말하면, 고유 한 nullable 열 (또는 열 집합)은 한 번만 NULL (또는 NULL 레코드)이 될 수 있습니다. 동일한 값 (NULL 포함)이 두 번 이상 있으면 고유 제약 조건을 위반하는 것이 분명하기 때문입니다.

그러나 이것이 "고유 한 nullable 열"개념이 유효 함을 의미하지는 않습니다. 관계형 데이터베이스에서 실제로 구현하려면 이러한 종류의 데이터베이스가 제대로 작동하도록 정규화되어야하며, 정규화에는 일반적으로 엔터티 간의 관계를 설정하기 위해 여러 (엔티티가 아닌) 추가 테이블을 추가해야한다는 점을 명심해야합니다. .

하나의 "고유 한 nullable 열"만 고려하여 기본 예제를 살펴 보겠습니다. 더 많은 열로 쉽게 확장 할 수 있습니다.

다음과 같은 테이블로 표시된 정보를 가정합니다.

create table the_entity_incorrect
(
  id integer,
  uniqnull integer null, /* we want this to be "unique and nullable" */
  primary key (id)
);

uniqnull을 분리하고 두 번째 테이블을 추가하여 uniqnull 값과 the_entity 사이의 관계를 설정하여이를 수행 할 수 있습니다 (uniqnull이 the_entity "내부"에있는 대신).

create table the_entity
(
  id integer,
  primary key(id)
);

create table the_relation
(
  the_entity_id integer not null,
  uniqnull integer not null,

  unique(the_entity_id),
  unique(uniqnull),
  /* primary key can be both or either of the_entity_id or uniqnull */
  primary key (the_entity_id, uniqnull), 
  foreign key (the_entity_id) references the_entity(id)
);

uniqnull 값을 the_entity의 행에 연결하려면 the_relation에 행을 추가해야합니다.

the_entity의 행에 대해 uniqnull 값이 연결되지 않은 경우 (즉, the_entity_incorrect에 NULL을 넣은 값) the_relation에 행을 추가하지 않습니다.

uniqnull의 값은 모든 the_relation에 대해 고유하며, the_entity의 각 값에 대해 기본 및 외래 키가이를 적용하기 때문에 the_relation에 최대 하나의 값이있을 수 있습니다.

그런 다음 uniqnull의 값 5가 the_entity id 3과 연결되는 경우 다음을 수행해야합니다.

start transaction;
insert into the_entity (id) values (3); 
insert into the_relation (the_entity_id, uniqnull) values (3, 5);
commit;

그리고 the_entity에 대한 id 값 10에 uniqnull 대응 항목이 없으면 다음 작업 만 수행합니다.

start transaction;
insert into the_entity (id) values (10); 
commit;

이 정보를 비정규 화하고 the_entity_incorrect와 같은 테이블이 보유 할 데이터를 얻으려면 다음을 수행해야합니다.

select
  id, uniqnull
from
  the_entity left outer join the_relation
on
  the_entity.id = the_relation.the_entity_id
;

"왼쪽 외부 조인"연산자는 the_entity의 모든 행이 결과에 나타나도록하여 the_relation에 일치하는 열이없는 경우 uniqnull 열에 NULL을 넣습니다.

잘 정규화 된 데이터베이스 (및 이에 상응하는 비정규 화 뷰 및 절차)를 설계하는 데 며칠 (또는 몇 주 또는 몇 달) 동안 소요 된 모든 노력은 수년 (또는 수십 년)의 고통과 낭비되는 리소스를 절약 할 수 있다는 점을 기억하십시오.


6
이미 50 개의 upvotes로 수락 된 답변의 의견에 언급했듯이 MS SQL Server는 고유 한 것으로 인덱싱 된 열에 여러 개의 null을 갖도록 지원해야합니다. 이를 허용하지 않는 SQL 표준을 구현하는 것은 실패입니다. Null은 값이 아니고, null은 null과 같지 않습니다. 이는 연도 이후의 기본 SQL 규칙입니다. 따라서 첫 번째 문장이 잘못되었으며 대부분의 독자는 계속 읽는 것을 귀찮게하지 않을 것입니다.
Frédéric
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.