이 시나리오의 올바른 구조는 하위 클래스 / 상속 모델이며이 답변에서 제안한 개념과 거의 동일합니다. 이기종 순서의 값 목록 .
이 질문에서 제안 된 모델은 Animal
실체에 유형 (예 :) race
과 모든 유형에 공통적 인 속성이 포함되어 있다는 점에서 매우 가깝습니다 . 그러나 두 가지 사소한 변경이 필요합니다.
해당 엔티티에서 Cat_ID 및 Dog_ID 필드를 제거하십시오.
여기서 핵심 개념 은 : ,, 등에 관계없이 모든 것이라는 것 입니다 . 포인트를 시작하는 것은, 특정 점을 감안 의이 진정 이후 별도의 식별자를 필요로하지 않는다 :Animal
race
Cat
Dog
Elephant
race
Animal
- 는
Animal_ID
고유
Cat
, Dog
및 추가적인 race
향후에 추가 엔티티는, 그 자체로 완전히 특정 표현하지 않는다 Animal
; 부모 엔터티에 포함 된 정보와 함께 사용될 때만 의미가 Animal
있습니다.
따라서, Animal_ID
의 property에서 Cat
, Dog
등 엔티티는 PK와 FK로 뒤로 모두 인 Animal
엔티티.
유형의 구별 breed
:
두 속성이 동일한 이름을 공유한다고해서 동일한 이름이 그러한 관계를 암시 하더라도 해당 속성이 반드시 동일한 것은 아닙니다 . 이 경우, 당신이 정말이 것은 실제로 및 별도의 "유형"으로CatBreed
DogBreed
초기 메모
- SQL은 Microsoft SQL Server에만 적용됩니다 (예 : T-SQL). 즉, 모든 RDBMS에서 데이터 유형이 동일하지 않으므로 데이터 유형에주의하십시오. 예를 들어, 나는 사용하고
VARCHAR
있지만 표준 ASCII 세트 이외의 것을 저장 해야하는 경우 실제로 사용해야 NVARCHAR
합니다.
- "type"테이블 (
Race
,, CatBreed
및 DogBreed
) 의 ID 필드 는 응용 프로그램 상수 (예 : 응용 프로그램의 일부)이기 때문에 자동 증가 하지 않습니다 (예 : T-SQL의 관점에서 IDENTITY). enum
C # (또는 다른 언어)에서 s로 표시됩니다 . 값이 추가되면 제어 된 상황에서 추가됩니다. 응용 프로그램을 통해 들어오는 사용자 데이터에 자동 증분 필드를 사용합니다.
- 내가 사용하는 명명 규칙은 기본 클래스 이름으로 시작하여 하위 클래스 이름으로 시작하는 각 하위 클래스 테이블의 이름을 지정하는 것입니다. 이를 통해 테이블을 구성하고 서브 클래스 테이블과 기본 엔티티 테이블의 관계를 명확하게 (FK를 보지 않고) 표시 할 수 있습니다.
- 보기에 대한 참고 사항은 마지막에있는 "최종 편집"섹션을 참조하십시오.
"레이스"별 접근 방식으로 "품종"
이 첫 번째 테이블 세트는 조회 / 유형 테이블입니다.
CREATE TABLE Race
(
RaceID INT NOT NULL PRIMARY KEY
RaceName VARCHAR(50) NOT NULL
);
CREATE TABLE CatBreed
(
CatBreedID INT NOT NULL PRIMARY KEY,
BreedName VARCHAR(50),
CatBreedAttribute1 INT,
CatBreedAttribute2 VARCHAR(10)
-- other "CatBreed"-specific properties as needed
);
CREATE TABLE DogBreed
(
DogBreedID INT NOT NULL PRIMARY KEY,
BreedName VARCHAR(50),
DogBreedAttribute1 TINYINT
-- other "DogBreed"-specific properties as needed
);
이 두 번째 목록은 주요 "동물"실체입니다.
CREATE TABLE Animal
(
AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
RaceID INT NOT NULL, -- FK to Race
Name VARCHAR(50)
-- other "Animal" properties that are shared across "Race" types
);
ALTER TABLE Animal
ADD CONSTRAINT [FK_Animal_Race]
FOREIGN KEY (RaceID)
REFERENCES Race (RaceID);
이 세 번째 테이블 세트는 각각 Race
의 정의를 완료하는 무료 서브 클래스 엔티티 입니다 Animal
.
CREATE TABLE AnimalCat
(
AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
CatBreedID INT NOT NULL, -- FK to CatBreed
HairColor VARCHAR(50) NOT NULL
-- other "Cat"-specific properties as needed
);
ALTER TABLE AnimalCat
ADD CONSTRAINT [FK_AnimalCat_CatBreed]
FOREIGN KEY (CatBreedID)
REFERENCES CatBreed (CatBreedID);
ALTER TABLE AnimalCat
ADD CONSTRAINT [FK_AnimalCat_Animal]
FOREIGN KEY (AnimalID)
REFERENCES Animal (AnimalID);
CREATE TABLE AnimalDog
(
AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
DogBreedID INT NOT NULL, -- FK to DogBreed
HairColor VARCHAR(50) NOT NULL
-- other "Dog"-specific properties as needed
);
ALTER TABLE AnimalDog
ADD CONSTRAINT [FK_AnimalDog_DogBreed]
FOREIGN KEY (DogBreedID)
REFERENCES DogBreed (DogBreedID);
ALTER TABLE AnimalDog
ADD CONSTRAINT [FK_AnimalDog_Animal]
FOREIGN KEY (AnimalID)
REFERENCES Animal (AnimalID);
공유 breed
유형을 사용하는 모델 은 "추가 메모"섹션 뒤에 표시됩니다.
추가 사항
- 의 개념은
breed
혼란의 초점이되는 것 같습니다. jcolebrand (질문에 대한 의견) breed
는 다른 race
s에서 공유되는 속성 이며 다른 두 가지 답변은 모델과 같이 통합되어 있습니다. 그러나의 값 breed
이 서로 다른 값에서 공유되지 않기 때문에 이것은 실수 입니다 race
. 예, 다른 두 가지 제안 된 모델이 race
의 부모 를 만들어이 문제를 해결하려고 시도한다는 것을 알고 breed
있습니다. 이것이 기술적으로 관계 문제를 해결하는 반면, 일반적이지 않은 속성에 대해 수행 할 작업 또는가없는 속성을 처리하는 방법에 대한 전반적인 모델링 문제를 해결하는 데 도움 race
이되지는 않습니다 breed
. 그러나 그러한 재산이 모든 곳에서 존재할 수있는 경우Animal
s, 그 옵션도 포함하겠습니다 (아래).
- vijayp과 DavidN이 제안한 모델은 다음과 같은 이유로 작동하지 않습니다.
- 그들은
- 일반적이지 않은 속성을 저장하지 못하도록
Animal
하거나 (적어도 개별 인스턴스에 대해 )
- 모든 데이터
race
의 모든 속성 Animal
은이 데이터를 나타내는 매우 평평하고 (관계가 거의없는) 엔터티에 저장되어야합니다 . 그렇습니다. 사람들은 항상이 작업을 수행하지만 해당 속성에 적합하지 않은 속성에 대해 행당 많은 NULL 필드를 가지며 해당 레코드 race
의 특정 필드와 관련된 행당 필드를 알고 race
있어야합니다.
- 나중에 속성으로 포함 되지 않은
race
의 를 추가 할 수 Animal
없습니다 breed
. 그리고 모든 경우에도 Animal
의가있다 breed
, 그 때문에 이전에 대해 언급 된 내용에 대한 구조 변하지 않을 것입니다 breed
: breed
온 의존을 race
(즉, breed
위해이 Cat
같은 일이 아니다 breed
에 대한 Dog
).
공통 / 공유 속성 접근 방식으로 "사육"
참고 사항 :
아래의 SQL은 위에 제시된 모델과 동일한 데이터베이스에서 실행될 수 있습니다.
Race
테이블은 동일
Breed
표는 새로운
- 세 개의
Animal
테이블이 추가되었습니다2
Breed
현재는 일반적인 자산 임에도 불구하고 Race
(기술적으로 관계가 정확하더라도) 주 / 부모 단체에 언급 되지 않은 것이 옳지 않은 것 같습니다 . 그래서, 모두 RaceID
와 BreedID
표현된다 Animal2
. 사이의 불일치 방지하기 위해 RaceID
에 주목 Animal2
하고 BreedID
다른위한 즉 RaceID
, I 모두에 FK 추가 한 RaceID, BreedID
것을 참조합니다에서 해당 필드의 UNIQUE CONSTRAINT Breed
테이블. 나는 일반적으로 FK가 고유 제약 조건을 가리키는 것을 멸시하지만, 그렇게하는 몇 가지 유효한 이유 중 하나입니다. UNIQUE CONSTRAINT는 논리적으로 "대체 키"이므로이 용도에 유효합니다. 또한 Breed
테이블에는 여전히 PK가 있습니다 BreedID
.
- 결합 된 필드에서 PK 만 사용하지 않고 UNIQUE CONSTRAINT가없는 이유는
BreedID
서로 다른 값 에서 동일한 값을 반복 할 수 있기 때문입니다 RaceID
.
- PK와 UNIQUE CONSTRAINT를 전환하지 않는 이유는 이것이의 유일한 사용법이
BreedID
아니기 때문에 가용 한 값이 Breed
없는 특정 값을 계속 참조 할 수 있어야하기 때문 RaceID
입니다.
- 다음 모델은 작동하지만 공유 개념에 관한 두 가지 잠재적 결함이 있습니다
Breed
(그리고 내가 Race
특정 Breed
테이블을 선호하는 이유 ).
- 의 모든 값이
Breed
동일한 속성 을 갖는다 는 암시적인 가정이 있습니다. 이 모델에는 Dog
"품종"과 Elephant
"품종" 간에 서로 다른 속성을 갖는 쉬운 방법이 없습니다 . 그러나 여전히 "최종 편집"섹션에 설명되어 있습니다.
Breed
둘 이상의 인종 을 공유 할 수있는 방법이 없습니다 . 그것이 바람직한 지 (또는 동물의 개념이 아니라 아마도이 유형의 모델을 사용하는 다른 상황에서) 확실하지는 않지만 여기서는 불가능합니다.
CREATE TABLE Race
(
RaceID INT NOT NULL PRIMARY KEY,
RaceName VARCHAR(50) NOT NULL
);
CREATE TABLE Breed
(
BreedID INT NOT NULL PRIMARY KEY,
RaceID INT NOT NULL, -- FK to Race
BreedName VARCHAR(50)
);
ALTER TABLE Breed
ADD CONSTRAINT [UQ_Breed]
UNIQUE (RaceID, BreedID);
ALTER TABLE Breed
ADD CONSTRAINT [FK_Breed_Race]
FOREIGN KEY (RaceID)
REFERENCES Race (RaceID);
CREATE TABLE Animal2
(
AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
RaceID INT NOT NULL, -- FK to Race, FK to Breed
BreedID INT NOT NULL, -- FK to Breed
Name VARCHAR(50)
-- other properties common to all "Animal" types
);
ALTER TABLE Animal2
ADD CONSTRAINT [FK_Animal2_Race]
FOREIGN KEY (RaceID)
REFERENCES Race (RaceID);
-- This FK points to the UNIQUE CONSTRAINT on Breed, _not_ to the PK!
ALTER TABLE Animal2
ADD CONSTRAINT [FK_Animal2_Breed]
FOREIGN KEY (RaceID, BreedID)
REFERENCES Breed (RaceID, BreedID);
CREATE TABLE AnimalCat2
(
AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
HairColor VARCHAR(50) NOT NULL
);
ALTER TABLE AnimalCat2
ADD CONSTRAINT [FK_AnimalCat2_Animal2]
FOREIGN KEY (AnimalID)
REFERENCES Animal2 (AnimalID);
CREATE TABLE AnimalDog2
(
AnimalID INT NOT NULL PRIMARY KEY,
HairColor VARCHAR(50) NOT NULL
);
ALTER TABLE AnimalDog2
ADD CONSTRAINT [FK_AnimalDog2_Animal2]
FOREIGN KEY (AnimalID)
REFERENCES Animal2 (AnimalID);
최종 편집 (다행히 ;-)
- 타입간에 서로 다른 특성을 운반 할 가능성 (후 어려움)에 대해서는
Breed
, 그것 인 동일한 서브 클래스 / 상속 개념이지만 함께 채용 할 수 Breed
메인 엔티티로한다. 이 설정에서 Breed
테이블의 모든 유형에 공통된 속성 것 Breed
(단지 등 Animal
테이블)과 RaceID
유형을 나타내는 것이다 Breed
(그것은에서와 동일하게 Animal
테이블). 그러면 BreedCat
, 등의 서브 클래스 테이블이 생깁니다 BreedDog
. 소규모 프로젝트의 경우 이것은 "과도한 엔지니어링"으로 간주 될 수 있지만, 이점이있는 상황에 대한 옵션으로 언급되고 있습니다.
두 가지 방법 모두 뷰를 전체 엔터티에 대한 바로 가기로 만드는 데 도움이되는 경우가 있습니다. 예를 들어, 다음을 고려하십시오.
CREATE VIEW Cats AS
SELECT an.AnimalID,
an.RaceID,
an.Name,
-- other "Animal" properties that are shared across "Race" types
cat.CatBreedID,
cat.HairColor
-- other "Cat"-specific properties as needed
FROM Animal an
INNER JOIN AnimalCat cat
ON cat.AnimalID = an.AnimalID
-- maybe add in JOIN(s) and field(s) for "Race" and/or "Breed"
- 논리적 엔터티의 일부는 아니지만 적어도 레코드가 삽입 및 업데이트되는시기를 파악하기 위해 테이블에 감사 필드를 갖는 것이 일반적입니다. 실제적인 관점에서 :
CreatedDate
필드가 추가 될 Animal
테이블. 이 필드는 서브 클래스 테이블 (예 :)에서 필요하지 않습니다. AnimalCat
두 테이블에 삽입되는 행이 트랜잭션 내에서 동시에 수행되어야하기 때문입니다.
LastModifiedDate
필드에 추가 될 Animal
테이블 및 모든 서브 클래스 테이블. 이 필드는 해당 특정 테이블이 업데이트 된 경우에만 업데이트됩니다. 업데이트가 발생 AnimalCat
하지만 Animal
특정 에 대해서는 업데이트 되지 않으면 AnimalID
해당 LastModifiedDate
필드 만 AnimalCat
설정됩니다.