私は、Jeff Smith の「SQL Server でのテーブル継承の実装」で説明されている手法に従っています(これは、この種の構造を実装するための事実上のアプローチのようです)。実表には、その3 つのサブタイプ表、、People
と 1 : 0..1 の関係があります。これは、従来、サブタイプ テーブルの主キーをベース テーブルへの外部キーとして定義することによって行われていました。Students
Teachers
Parents
サブタイプ間で排他性を強制する (同じ人が同時に生徒と教師になるのを防ぐ) ために、作成者PersonTypeID
は永続化された計算列として各サブタイプ テーブルに追加し、それをベース テーブルの外部キー制約に含めることをお勧めします。
CREATE TABLE PersonType
(
PersonTypeID INT PRIMARY KEY,
Description VARCHAR(10)
);
INSERT INTO PersonType
VALUES (1, 'Student'),
(2, 'Teacher'),
(3, 'Parent');
CREATE TABLE People
(
PersonID INT PRIMARY KEY,
PersonTypeID INT REFERENCES PersonType (PersonTypeID),
Name VARCHAR(10),
UNIQUE (PersonID, PersonTypeID)
)
CREATE TABLE Students
(
PersonID INT PRIMARY KEY,
PersonTypeID AS 1 PERSISTED, -- student
EnrollmentDate DATETIME,
FOREIGN KEY (PersonID, PersonTypeID) REFERENCES People (PersonID, PersonTypeID)
)
CREATE TABLE Teachers
(
PersonID INT PRIMARY KEY,
PersonTypeID AS 2 PERSISTED, -- teacher
HireDate DATETIME,
FOREIGN KEY (PersonID, PersonTypeID) REFERENCES People (PersonID, PersonTypeID)
)
CREATE TABLE Parents
(
PersonID INT PRIMARY KEY,
PersonTypeID AS 3 PERSISTED, -- parents
DifficultyScore INT,
FOREIGN KEY (PersonID, PersonTypeID) REFERENCES People (PersonID, PersonTypeID)
)
ただし、このアプローチには多くの問題があります。
- 各サブタイプ テーブルで追加の列を無駄にします。
- 実表に一意制約を追加する必要があります。これにより、より多くのスペースが浪費され (一意のインデックスとして実装されるため)、ベース テーブルへの更新が遅くなります。
- 外部キー制約には、(1 つではなく) 2 つの列のチェックが含まれるため、サブタイプ テーブルへの更新が遅くなります。
私の仮説は、代わりにスカラー関数を介してチェック制約を使用して一意性を強制する方がよいというものです。これにより、余分な列と一意のインデックスのための無駄なストレージがなくなり、ベース テーブルへの更新が高速化され、複合外部キーと同じパフォーマンスがサブタイプ テーブルへの更新で達成される可能性があります。
CREATE TABLE People
(
PersonID INT PRIMARY KEY,
PersonTypeID INT REFERENCES PersonType (PersonTypeID),
Name VARCHAR(10)
)
CREATE FUNCTION GetPersonTypeID (@PersonID INT)
RETURNS INT
AS
BEGIN
RETURN
(
SELECT PersonTypeID
FROM People
WHERE PersonID = @PersonID
)
END;
CREATE TABLE Students
(
PersonID INT PRIMARY KEY REFERENCES People (PersonID)
CHECK (dbo.GetPersonTypeID(PersonID) = 1),
EnrollmentDate DATETIME
)
CREATE TABLE Teachers
(
PersonID INT PRIMARY KEY REFERENCES People (PersonID)
CHECK (dbo.GetPersonTypeID(PersonID) = 2),
HireDate DATETIME
)
CREATE TABLE Parents
(
PersonID INT PRIMARY KEY REFERENCES People (PersonID)
CHECK (dbo.GetPersonTypeID(PersonID) = 3),
DifficultyScore INT
)
このアプローチを使用しない理由はありますか?