복합 기본 키의 Null 허용 열에 어떤 문제가 있습니까?
ORACLE은 기본 키를 구성하는 열에서 NULL 값을 허용하지 않습니다. 대부분의 다른 "엔터프라이즈 수준"시스템에서도 마찬가지입니다.
동시에, 대부분의 시스템은 널 입력 가능 컬럼에 고유 한 제한 조건 을 허용합니다.
고유 제한 조건에 NULL이있을 수 있지만 기본 키가없는 이유는 무엇입니까? 이것에 대한 근본적인 논리적 이유가 있습니까, 아니면 이것이 기술적 한계가 있습니까?
기본 키는 행을 고유하게 식별하기위한 것입니다. 이것은 키의 모든 부분을 입력과 비교하여 수행됩니다.
정의에 따라 NULL은 성공적인 비교의 일부가 될 수 없습니다. 자체 비교 ( NULL = NULL
)도 실패합니다. 이는 NULL을 포함하는 키가 작동하지 않음을 의미합니다.
또한 외래 키에서는 NULL을 사용하여 선택적 관계를 표시 할 수 있습니다. (*) PK에서도 허용하면이 문제가 발생합니다.
(*) 주의 사항 : 널 입력 가능 외래 키를 갖는 것은 관계형 데이터베이스 설계가 깨끗하지 않습니다.
이 두 개의 엔티티 인 경우 A
와 B
위치를 A
선택적으로 관련 될 수있다 B
, 깨끗한 솔루션은 해상도 테이블을 만드는 것입니다 (의 말을하자 AB
). 그 표는 연결 것 A
으로 B
:이 경우 입니다 관계가 있다면 그것은, 기록을 포함하는 것 아니다 는 않을 것 다음.
기본 키는 테이블의 모든 행에 대한 고유 식별자를 정의 합니다. 테이블에 기본 키가 있으면 원하는 행을 선택할 수 있습니다.
고유 제한 조건이 반드시 모든 행을 식별하지는 않습니다. 그냥하도록 지정 하면 행이 컬럼의 값을 가지고, 다음, 그들이 고유해야합니다. 이것은 모든 행 을 고유하게 식별하기에는 충분하지 않으므로 기본 키가 수행해야합니다.
기본적으로 다중 열 기본 키의 NULL에는 아무런 문제가 없습니다. 그러나 디자이너가 의도하지 않은 의미를 갖는 것은 많은 시스템에서 오류가 발생하는 이유입니다.
일련의 필드로 저장된 모듈 / 패키지 버전의 경우를 고려하십시오.
CREATE TABLE module
(name varchar(20) PRIMARY KEY,
description text DEFAULT '' NOT NULL);
CREATE TABLE version
(module varchar(20) REFERENCES module,
major integer NOT NULL,
minor integer DEFAULT 0 NOT NULL,
patch integer DEFAULT 0 NOT NULL,
release integer DEFAULT 1 NOT NULL,
ext varchar(20),
notes text DEFAULT '' NOT NULL,
PRIMARY KEY (module, major, minor, patch, release, ext));
기본 키의 처음 5 개 요소는 정기적으로 릴리스 버전의 일부로 정의되지만 일부 패키지에는 일반적으로 정수가 아닌 사용자 정의 된 확장자 (예 : "rc-foo"또는 "vanilla"또는 "beta"또는 기타 다른 것)가 있습니다. 누구 네 개의 필드은) 꿈을 꿀 수도 부족하다. 패키지에 확장명이 없으면 위의 모델에서 NULL이며, 그렇게 놔두면 아무런 해가 없습니다.
그러나 NULL 은 무엇 입니까? 그것은 정보 의 부족 , 알 수없는 것으로 나타납니다 . 즉, 아마도 이것이 더 의미가 있습니다.
CREATE TABLE version
(module varchar(20) REFERENCES module,
major integer NOT NULL,
minor integer DEFAULT 0 NOT NULL,
patch integer DEFAULT 0 NOT NULL,
release integer DEFAULT 1 NOT NULL,
ext varchar(20) DEFAULT '' NOT NULL,
notes text DEFAULT '' NOT NULL,
PRIMARY KEY (module, major, minor, patch, release, ext));
이 버전에서 튜플의 "ext"부분은 NULL이 아니지만 기본값은 비어있는 문자열입니다. 이는 의미 상 (실제로는) NULL과 다릅니다. NULL은 알 수없는 반면, 빈 문자열은 "무엇이 존재하지 않는"의도적 인 레코드입니다. 다시 말해, "빈"과 "널"은 다른 것입니다. "여기에 가치가 없습니다"와 "여기에 가치가 무엇인지 모르겠습니다."의 차이점이 있습니다.
버전 확장이없는 패키지를 등록하면 확장이 없다는 것을 알고 있으므로 빈 문자열이 실제로 올바른 값입니다. NULL은 확장명이 있는지 여부를 모르거나 그것이 무엇인지 알았지 만 모르는 경우에만 정확합니다. 문자열 값이 표준 인 시스템에서는이 상황을 다루기가 더 쉽습니다. 0 또는 1을 삽입하는 것 이외의 "빈 정수"를 나타내는 방법이 없으므로 나중에 비교할 때 롤업됩니다. 자체 의미) *.
우연히 두 방법 모두 Postgres에서 유효하지만 "엔터프라이즈"RDMBS에 대해 논의하고 있기 때문에 NULL == "모름"이기 때문에 비교 결과에 NULL을 던질 때 비교 결과가 약간 다를 수 있습니다. 알려지지 않은 것을 알 수 없으므로 NULL을 포함하는 비교 결과가 NULL입니다. 위험! 이것에 대해 신중하게 생각하십시오. 이것은 NULL 비교 결과 가 일련의 비교를 통해 전파됨 을 의미합니다 . 이것은 정렬, 비교 등의 미묘한 버그의 원인이 될 수 있습니다.
Postgres는 귀하가 성인이라고 가정하고 스스로 결정할 수 있습니다. Oracle과 DB2는 당신이 어리석은 짓을하고 있다는 것을 몰랐으며 오류를 던졌다 고 가정합니다. 이것은 일반적 으로 올바른 일이지만 항상 그런 것은 아닙니다 . 어떤 경우에는 실제로 알지 못하고 NULL을 가질 수 있으므로 의미있는 비교가 불가능한 알 수없는 요소가있는 행을 남기는 것이 올바른 동작입니다.
어쨌든 전체 스키마에서 허용하는 NULL 필드 수를 제거하고 기본 키의 일부인 필드에 대해서는 이중으로 제거해야합니다. 대부분의 경우 NULL 열의 존재는 정규화되지 않은 (고의적으로 비정규 화되지 않은) 스키마 설계를 나타내며 허용되기 전에 매우 열심히 생각해야합니다.
[* NOTE: It is possible to create a custom type that is the union of integers and a "bottom" type that would semantically mean "empty" as opposed to "unknown". Unfortunately this introduces a bit of complexity in comparison operations and usually being truly type correct isn't worth the effort in practice as you shouldn't be permitted many NULL
values at all in the first place. That said, it would be wonderful if RDBMSs would include a default BOTTOM
type in addition to NULL
to prevent the habit of casually conflating the semantics of "no value" with "unknown value".]
NULL == NULL -> false (at least in DBMSs)
So you wouldn't be able to retrieve any relationships using a NULL value even with additional columns with real values.
The answer by Tony Andrews is a decent one. But the real answer is that this has been a convention used by relational database community and is NOT a necessity. Maybe it is a good convention, maybe not.
Comparing anything to NULL results in UNKNOWN (3rd truth value). So as has been suggested with nulls all traditional wisdom concerning equality goes out the window. Well that's how it seems at first glance.
But I don't think this is necessarily so and even SQL databases don't think that NULL destroys all possibility for comparison.
Run in your database the query SELECT * FROM VALUES(NULL) UNION SELECT * FROM VALUES(NULL)
What you see is just one tuple with one attribute that has the value NULL. So the union recognized here the two NULL values as equal.
When comparing a composite key that has 3 components to a tuple with 3 attributes (1, 3, NULL) = (1, 3, NULL) <=> 1 = 1 AND 3 = 3 AND NULL = NULL The result of this is UNKNOWN.
But we could define a new kind of comparison operator eg. ==. X == Y <=> X = Y OR (X IS NULL AND Y IS NULL)
Having this kind of equality operator would make composite keys with null components or non-composite key with null value unproblematic.
I still believe this is a fundamental / functional flaw brought about by a technicality. If you have an optional field by which you can identify a customer you now have to hack a dummy value into it, just because NULL != NULL, not particularly elegant yet it is an "industry standard"
'Programing' 카테고리의 다른 글
HttpClient를 사용하는 Java의 Http 기본 인증? (0) | 2020.06.18 |
---|---|
Visual Studio Code에서 사이드 바를 숨기는 바로 가기가 있습니까? (0) | 2020.06.18 |
MissingManifestResourceException은 무슨 뜻이고 어떻게 해결 하죠? (0) | 2020.06.18 |
dplyr tbl 열을 벡터로 추출 (0) | 2020.06.17 |
Windows의 Python 3에서 MySQL에 어떻게 연결할 수 있습니까? (0) | 2020.06.17 |