UNIQUE 제약 조건이 하나의 NULL 만 허용하는 이유는 무엇입니까?


36

기술적으로 NULL = NULL은 False입니다.이 논리에 의해 NULL은 NULL과 같지 않으며 모든 NULL은 고유합니다. 이것은 모든 NULL이 고유하고 고유 인덱스가 많은 수의 NULL을 허용해야 함을 의미하지 않습니까?


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
폴 화이트 GoFundMonica 말한다

답변:


52

왜 이런 식으로 작동합니까? 과거로 돌아가서 누군가가 표준이 말하는 것에 대해 알거나 신경 쓰지 않고 디자인 결정을 내 렸습니다 NULL. 이 결정은 경우에 NULL = NULL

현명한 결정은 아니 었습니다. 그들이해야 할 일은 기본 동작이 ANSI 표준을 준수하는 것입니다.이 독특한 동작을 실제로 원한다면 WITH CONSIDER_NULLS_EQUALor 같은 DDL 옵션을 통해 허용하십시오 WITH ALLOW_ONLY_ONE_NULL.

물론, 가늠자는 20/20입니다.

그리고 우리는 어쨌든 가장 깨끗하거나 직관적이지 않더라도 해결 방법을 가지고 있습니다.

필터링 된 고유 인덱스를 만들어 SQL Server 2008 이상에서 올바른 ANSI 동작을 얻을 수 있습니다.

CREATE UNIQUE INDEX foo ON dbo.bar(key) WHERE key IS NOT NULL;

NULL이러한 행은 중복 검사에서 완전히 제외되므로 둘 이상의 값을 허용 합니다. 또한 보너스로 여러 NULL개가 허용 된 경우 (특히 인덱스의 유일한 열이 아니고 열이있는 경우) 전체 테이블로 구성된 인덱스보다 작은 인덱스가 됩니다 INCLUDE. 그러나 필터링 된 인덱스의 다른 제한 사항을 알고 싶을 수도 있습니다.


8

옳은. SQL Server에서 고유 제한 조건 또는 색인을 구현하면 하나의 NULL 만 허용됩니다. 또한 이것은 기술적으로 NULL의 정의와 맞지 않지만 "기술적으로"정확하지 않더라도 더 유용하게 만드는 것들 중 하나입니다. PRIMARY KEY (고유 인덱스)는 NULL을 허용하지 않습니다 (물론).


1
이 (SQL-Server) 기술도 SQL 표준에 맞지 않습니다. 이 문제와 관련하여 7 년 된 Connect 항목 이 있습니다.
ypercubeᵀᴹ

@ypercube True입니다. 그렇기 때문에 나는 그것이 단지 구현이라고 말했고 실제로 NULL의 정의와 맞지 않습니다. (나는 무엇을 위해 그것을 사용했습니다 있지만.) I는 필터링 된 고유 인덱스에 대해 생각하지 않았다
케네스 피셔을

3

먼저 "Null value"라는 문구 사용을 중지하면 실수로 이어질 수 있습니다. 대신 "널 마커"라는 문구를 사용하십시오.이 컬럼의 실제 값이 누락되었거나 적용 할 수 없음을 나타내는 컬럼의 마커입니다 (그러나 마커는 이러한 옵션 중 실제로 어떤 옵션이 1인지 표시하지 않습니다).

이제 다음을 상상해보십시오 (데이터베이스에 모델링 된 상황에 대한 완전한 지식이없는 경우).

Situation          Database

ID   Code          ID   Code
--   -----         --   -----
1    A             1    A
2    B             2    (null)
3    C             3    C
4    B             4    (null)

우리가 모델링하는 무결성 규칙은 "코드는 고유해야합니다"입니다. 실제 상황이이를 위반하므로 데이터베이스는 항목 2와 4가 동시에 테이블에있는 것을 허용하지 않아야합니다.

가장 안전하고 융통성이없는 방법은 코드 필드에서 널 마커를 허용하지 않는 것이므로 데이터가 일치하지 않을 가능성이 없습니다. 가장 유연한 방법은 여러 개의 null 마커를 허용하고 값을 입력 할 때 고유성에 대해 걱정하는 것입니다.

Sybase 프로그래머는 테이블에 하나의 널 마커 만 허용하는 다소 안전하고 유연하지 않은 접근 방식을 사용했습니다. Microsoft는이 동작을 계속했으며 이전 버전과의 호환성을 기대합니다.


¹ 나는 Codd가 두 개의 널 마커 (알 수없는 마커, 적용 할 수없는 마커)의 구현을 고려했지만 거부했지만 어쨌든 참조를 찾을 수 없다고 확신합니다. 내가 올바르게 기억하고 있습니까?

추신 : null에 대해 내가 가장 좋아하는 인용문 : Louis Davidson, "Professional SQL Server 2000 데이터베이스 디자인", Wrox Press, 2001, 페이지 52. "한 문장으로 마무리 : NULL은 악입니다."


1
싱글을 허용해도이 null목표를 달성 할 수 없습니다. 결 측값이 다른 행 중 하나의 값과 같을 수 있기 때문입니다.
Martin Smith

1
@MartinSmith가 말한 것. 점검 제한 조건이 있으면 어떻게 CHECK (Value IN ('A','B','C','D'))합니까? 그런 다음 SQL-Server의 구현과 SQL 표준 모두 테이블에 5 개의 행 (각 값에 대해 한 행에 NULL이있는 1을 더한 값)을 가질 수 있도록합니다. 그런 다음 데이터베이스는 제약 조건과 일치하지만 디자이너의 의도와 일치하지 않습니다. 최대 4 행의 테이블. 하나 이상의 행이 삭제되지 않는 한 제약 조건을 위반하지 않는 NULL로 변경할 수있는 값은 없습니다.
ypercubeᵀᴹ

1
표준이 5 대신 6 행에서 106 행까지 허용한다는 사실은이 시나리오에서 둘 다 실패한다고 변경하지 않습니다.
ypercubeᵀᴹ

@Martin Smith, 데이터베이스 서버가 알 수 없으므로 위험하지 않으며 안전한 경로를 사용합니다. 이것이 Sybase (I 추정) 프로그래머가 결정한 것입니다. (최소한 나의 책장에서 가장 오래된 책인 Inside SQL Server 6.5까지는 Ron Soukup이 Aaron Bertrand가 그의 답변에서하는 것과 거의 같은 의견을 냈습니다) . 나는 그것이 더 나쁠 수 있다고 생각한다. :-)
Greenstone Walker

2
@GreenstoneWalker- "안전한"경로를 사용하지 않습니다. 결 측값이 충돌하지 않는다고 가정합니다. CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;오류가 발생합니다. NULL불완전한 지식은 가치가 다르다는 것을 보장하지 않기 때문에 디자인 동기에 대한 이론에 따르면 첫 번째 경우에 삽입을 막아야했을 것입니다.
Martin Smith

2

이것은 기술적으로 정확하지는 않지만 철학적으로 밤에 잠을 자는데 도움이됩니다 ...

다른 사람들이 말했거나 암시 한 것처럼 NULL을 알 수없는 것으로 생각하면 하나의 NULL 값이 실제로 다른 NULL 값과 같은지 여부를 결정할 수 없습니다. 이런 식으로 생각하면 NULL == NULL 표현식은 NULL로 평가되어야합니다.

고유 제한 조건은 열 값을 비교하기 위해 결정적인 값이 필요합니다. 즉, 항등 연산자를 사용하여 단일 열 값을 다른 열 값과 비교할 때 유효하려면 false로 평가해야합니다. 알 수없는 경우가 종종 허위로 취급 되더라도 실제로는 거짓이 아닙니다. 두 개의 NULL 값은 같거나 같지 않을 수 있습니다. 단순히 결정하기가 어렵습니다.

고유 제한 조건을 서로 구별 할 수있는 값을 제한하는 것으로 생각하면 도움이됩니다. 이것이 의미하는 바는 다음과 같은 SELECT를 실행하는 것입니다.

SELECT * from dbo.table1 WHERE ColumnWithUniqueContraint="some value"

고유 한 제약 조건이있는 경우 대부분의 사람들은 하나의 결과를 기대합니다. ColumnWithUniqueConstraint에서 여러 개의 NULL 값을 허용 한 경우 비교 값으로 NULL을 사용하여 테이블에서 하나의 고유 한 행을 선택할 수 없습니다.

따라서 NULL 정의와 관련하여 정확하게 구현되었는지 여부에 관계없이 여러 NULL 값을 허용하는 것보다 대부분의 상황에서 훨씬 더 실용적이라고 생각합니다.


고유 제한 조건 (SQL-Server뿐만 아니라 모든 구현에서)이있는 경우 Select는 1 개의 결과를 제공합니다. 요점이 뭐야?
ypercubeᵀᴹ

-3

UNIQUE제약 조건 의 주요 목적 중 하나는 중복 레코드를 방지하는 것입니다. 값을 "알 수없는"여러 레코드가있을 수있는 테이블이 필요하지만 두 레코드가 동일한 "알려진"값을 가질 수없는 경우 알 수없는 값에는 인공 고유 식별자를 할당해야합니다. 테이블에 추가되었습니다.

UNIQUE제약 조건이 있고 단일 null 값을 포함하는 열이 드문 경우가 몇 가지 있습니다. 예를 들어, 테이블에 열 값과 현지화 된 텍스트 설명 간의 매핑이 포함 된 경우 행 NULL을 사용하면 다른 테이블의 해당 열이 일 때 표시 될 설명을 정의 할 수 있습니다 NULL. 동작에 NULL따라 해당 사용 사례 가 허용됩니다.

그렇지 않으면 UNIQUE동일한 레코드가 많이 존재할 수 있도록 열에 제약 조건이 있는 데이터베이스에 대한 근거가 없지만 키 값을 구별 할 수없는 여러 레코드를 허용하면서이를 막을 방법이 없습니다. NULL그 자체와 같지 않다고 선언 하면 NULL값을 서로 구별 할 수 없습니다 .


3
인공 고유 식별자는 유감입니다. 죄송합니다. VIN을 위해 어떻게 하시겠습니까? 그것이 무엇인지 모른다면 왜 무언가를 만들어 내겠습니까? 추가 디스크 공간을 차지하기 위해? 다른 문제를 해결하는 것은 말도 안되는 것처럼 보입니다 (예 : NULL을 정상적으로 처리하는 방식으로 응용 프로그램을 작성하고 싶지 않은 것처럼). 왜 무언가가 NULL인지 (예를 들어 존재하지만 알 수없는 vs. 존재하지 않는지 알고 있거나 존재하지 않는지 아는 경우) 절대적으로 알아야하는 경우 일종의 상태 열을 추가하십시오. 토큰은 단지 다루기 어려운 까다로운 코드로 이어집니다.
Aaron Bertrand

고유성 제약의 목적에 따라 달라집니다. 필드가 식별자로 사용되는 경우 null이 아니어야합니다. (VIN과 마찬가지로) 비즈니스 규칙에 따라 항목이 두 번 나타날 때 그 중 하나가 잘못되어야하지만 일부 항목이 "모름"일 수 있다고 할 경우 고유성 제약 조건이 적절한 접근 방식으로 느껴지지 않습니다. 하나의 VIN이있는 차량이 있고 데이터베이스의 다른 차량과 충돌하는 경우 VIN 중 하나 이상이 잘못되었음을 알 수 있지만 데이터베이스가 추측보다 두 레코드에 대해 신뢰할 수있는 값을보고하도록하는 것이 좋습니다 그 중 하나가 맞습니다.
supercat

@AaronBertrand : 널 (null) 고유의 널 (null) 인 경우 널 (null)이 아닌 필드가 필드를 채우기 전에 (예 : "배우자 ID") 대리 키를 설정할 수없는 경우가 있습니다. "고유 한"제약은 불충분 할 것; X.Spouse가 널이 아닌 경우 X.Spouse.Spouse = X가 필요합니다. 또한, "배우자"와 같은 것은 미혼 인에 대한 기록이 배우자로서 "NULL"이 아니라 자신의 ID 여야한다고 말함으로써 처리 될 수 있습니다.이 경우 X.spouse.spouse = X 규칙은 모두에게 적용하십시오.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.